IO流概述
1.什么是IO流
存储和读取数据的解决方案
I:input O:output
流:像水一样传输数据
2.IO流的作用
用于读写数据(本地文件,网络)
3.IO按照流向可以分为哪两种流
输出流:程序 ——> 文件
输入流:文件 ——> 程序
4.IO流按照操作文件的类型可以分类成哪两种流
字节流:可以操作所有类型的文件
字符流:只能操作纯文本文件
5.什么是纯文本文件
用windows系统自带的记事本打开并且能读懂的文件
txt文件,md文件,xml文件,lrc文件等。
FileOutputStream
FileOutputStream原理
操作本地文件的字节输出流,可以把程序种的数据写到本地文件中。
书写步骤:
-
创建字节输出流对象
-
细节1:参数是字符串表示的路径或是File对象都是可以的
-
细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的
-
细节3:如果文件已经存在,则会清空文件
-
-
写数据
-
细节:write方法的参数是整数,但是实际上写到本地文件中的整数是在ASCII上对应的字符
-
-
释放数据
-
细节:每次使用完流之后都到释放资源
-
FileOutputStream写数据的3种方式
方法名称 | 说明 |
---|---|
void write(int b) | 一次写一个字节数据 |
void write(byte[] b) | 一次写一个字节数组数据 |
void write(byte[] b, int off, int len) | 一次写一个字节数组的部分数据 |
FileOutputStream换行写和续写
换行写:
-
再次写出一个换行符就可以了
-
windows: \r\n
-
Linux: \n
-
Mac: \r
-
细节:
在windows操作系统当中,java对回车换行进行了优化。 虽然完整的是\r\n,但是我们写其中一个\r或者\n java也可以实现换行,因为java在底层会补全
建议:
不要省略,还是写全了。
续写:
如果想要续写,打开续写开关即可。 开关位置:创建对象的第二个参数 默认false:表示关闭续写,此时创建对象会清空文件 手动传递true:表示打开续写,此时创建对象不会清空文件
总结
-
FileOutputStream的作用
-
可以把程序中的数据写到本地文件上,是字节流的基本流。
-
-
书写步骤
-
创建对象,写出数据,释放资源
-
-
三步操作的细节
-
创建对象:文件存在、文件不存在、追加写入
-
写出数据:写出整数、写出字节数据、换行写
-
释放资源:关闭通道
-
FileInputStream
FileInputStream原理
操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中来。
书写步骤:
-
创建字节输入流对象
-
细节1:如果文件不存在,就直接报错。
-
java为什么会这么设计呢?
-
输出流:不存在文件,创建一个
-
把数据写到文件当中
-
-
输入流:不存在文件,而是报错呢?
-
因为创建出来的文件是没有数据的,没有任何意义。
-
所以java就没有设计这种无意义的逻辑,文件不存在直接报错。
-
-
程序中最重要的是:数据。
-
-
-
读取数据
-
细节1:一次读取一个字节,读取出来的是数据在ASCII上对应的数字
-
细节2:读到文件末尾了,read方法返回-1
-
-
释放资源
-
细节:每次使用完之后都要释放资源。
-
FileInputStream循环读取
案例:
//创建对象
FileInputStream fis = new FileInputStream("D:\\Code\\myio\\myIo\\a.txt");
//循环读取
int b ;
while ((b = fis.read()) != -1 ){
System.out.println((char) b);
}
//释放资源
fis.close();
错误案例:
//read:表示读取数据,而且是读取一次数据就移动一次指针
//创建对象
FileInputStream fis = new FileInputStream("D:\\Code\\myio\\myIo\\a.txt");
//循环读取
while ((fis.read()) != -1 ){
System.out.println(fis.read());//只返回部分的数据
}
//释放资源
fis.close();
FileInputStream读取的问题
IO流:如果拷贝的文件过大,那么速度会不会又影响?
方法名称 | 说明 |
---|---|
public int read() | 一次读一个字节数据 |
public int read(byte[] buffer) | 一个读一个字节数组数据 |
注意:一次读一个字节数组的数据,每次读取会尽可能把数组装满
一般都用:1024的整数倍 1024 * 1024 * 5
byte[] bytes = new byte[2];
//一次读取多个字节数据,具体读多少,跟数组的长度有关
//返回值:本次读取到了多少个字节数据
int len1 = fis.read();
System.out.println(len1);
//这里表示的是读取个数,并且他是从0位置进行读取,且读取很len1长。
String str1 = new String(bytes,0,len1);
System.out.println(str1);
字符集
字符集详解: (ASCII,GBK)
1、在计算机中,任意数据都是以二进制的形式来存储的。
2、计算机中最小的存储单元是一个字节
3、ASCII字符集中,一个英文在一个字节
4、简体中文版Windows,默认是使用GBK字符集
5、GBK字符集完全兼容ASCII字符集
一个英文占一个字节,二进制第一位是0.
一个中文占两个字节,二进制高位字节的第一位是1.
字符集详解: (Unicode)
1、Unicode字符集的UTF-8编码格式
一个英文占一个字节,二进制第一位是0,转成十进制是正数
一个中文占三个字节,二进制第一位是1,第一个字节转成十进制是负数
2、UTF不是字符集,只是一种编码格式
乱码
为什么会有乱码?
1、读取数据时未读完整个汉字。字节流:一个读取一个字节
2、编码和解码时的方式不统一
如何不产生乱码?
1、不要用字节流读取文本文件
2、编码解码时使用一个码表,同一个编码方式
扩展
字节流读取中文会乱码,但是为什么拷贝不会乱码呢?
因为他是整个文本中的字节读取并写出的。
Java中编码和解码的实现
Java中编码的方法
public byte[] getBytes() 使用默认方式进行编码
public byte[] getBytes(String charsetName) 使用指定方式进行编码
Java中解码的方法
String (byte[] bytes) 使用默认方式进行解码
String (byte[] bytes, String charsetName) 使用指定方式进行解码
案例:
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class study1 {
public static void main(String[] args) throws UnsupportedEncodingException {
//编码
String str = "ai你友";
byte[] bytes1 = str.getBytes();
System.out.println(Arrays.toString(bytes1));
byte[] bytes2 = str.getBytes("GBK");
System.out.println(Arrays.toString(bytes2));
//解码
String str2 = new String(bytes1);
System.out.println(str2);
String str3 = new String(bytes1,"GBK");
System.out.println(str3);
}
}
字符流
字符流概述
字节流的底层其实就是字节流
字符流 = 字节流 + 字符集
特点
输入流:一次读一个字节,遇到中文时,一个读多个字节
输出流:底层会把数据按照指定的编码方式进行编码,变成字节再写到文件中。
使用场景
对于纯文本文件进行读写操作
FileReader
第一步:创建对象
public FileReader(File file) 创建字符输入流关联本地文件
public FileReader(String pathname) 创建字符输入流关联本地文件
第二步:读取数据
public int read() 读取数据,读到末尾返回-1
public int read(char[] buffer) 读取多个数据,读到末尾返回-1
字符流的底层也是字节流,默认也是一个字节一个字节的读取的。
如果遇到中文就会一次读取多个,GBK一次读取两个字节,UTF—8一次读三个字节
read()细节:
1、read():默认也是一个字节一个字节的读取的,如果遇到中文就会一次读取多个
2、在读取之后,方法的底层还会进行解码并转成十进制。
最终把这个十进制作为返回值
这个十进制的数据也表示在字符集上的数字
英文:文件里面二进制数据 0110 0001
read方法进行读取,解码并转成十进制97
中文:文件里面的二进制数据 11100110 10110001 10001001
read方法进行读取,解码并转成十进制27721
如果想看见中文就把这些十进制,进行强转就可以了。
第三步:释放资源
public void close() 释放资源/关流
案例:
FileReader file = new FileReader("D:\\Code\\myio\\myIo\\a.txt");
char[] chars = new char[2];
int len;
//read(chars):读取数据,解码,强转三步合并了,把强转之后的字符放到数组当中
//空参的read + 强转类型转换
while ((len = file.read(chars)) != -1){
//把数组中的数据变成字符串在进行打印
System.out.print(new String(chars,0,len));
}
file.close();
FileWriter
第一步:创建对象
方法名称 | 说明 |
---|---|
public FileWriter(File file) | 创建字符输出流关联本地文件 |
public FIleWriter(String pathname) | 创建字符输出流关联本地文件 |
public FIleWriter(File file, boolean append) | 创建字符输出流关联本地文件,续写 |
public FIleWriter(String pathname, boolean append) | 创建字符输出流关联本地文件,续写 |
细节1:参数是字符串表示的路径或者File对象都是可以的
细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的
细节3:如果文件已经存在,则会清空文件,如果不想清空可以打开续写开关
第二步:读取数据
方法名称 | 说明 |
---|---|
void write(int c) | 写出一个字符 |
void write(String str) | 写出一个字符串 |
void write(String str, int off, int len) | 写出一个字符串的一部分 |
void write(char[] cbuf) | 写出一个字符数组 |
void write(char[] cbuf, int off, int len) | 写出字符数组的一部分 |
细节:如果write方法的参数是整数,但是实际上写到本地文件中的是整数在字符集对应的字符
第三步:释放资源
方法名称 | 说明 |
---|---|
public void close() | 释放资源/关流 |
细节:每次使用完之后都要进行释放。
字符流原理解析
-
创建字符输入流对象
-
底层:关联文件,并创建缓冲区(长度为8192的字节数组)
-
-
读取数据
-
底层:
-
判断缓冲区中是否有数据可以读取
-
缓冲区没有数据:就从文件中获取数据,装到缓冲区中,每次尽可能装满缓冲区
如果文件中也没有数据了,返回-1
-
缓冲区有数据:就从缓冲区中读取。
-
-
空参的read方法:一次读取一个字节,遇到中文一次读多个字节,把字节解码并转成十进制返回
有参的read方法:把读取字节,解码,强转三步合并了,强转之后的字符放到数组中
如果把缓存区的8192个字节用完之后,还有读取的就进行覆盖形式的读取。
flush和close方法
成员方法 | 说明 |
---|---|
public void flush() | 将缓冲区中的数据,刷新到本地文件中 |
public void close() | 释放资源/关流 |
flush刷新:刷新之后,还可以继续往文件中写数据(刷新之后是直接出现再文本当中)
close关流:断开通道,无法再往文件中写出数据
缓冲流
字节缓冲流
方法名称 | 说明 |
---|---|
public BufferedInputStream(InputStream is) | 把基本流包装成高级流,提高读取数据的性能 |
public BufferedOutputStream(OutputStream os) | 把基本流包装成高级流,提高写出数据的性能 |
原理:底层自带了长度为8192的缓冲区提高性能。
字节缓冲流提高速率的原理是它是在内存中进行运行的。
字符缓冲流
方法名称 | 说明 |
---|---|
public BufferedReader(Reader r) | 把基本流变成高级流 |
public BufferedWriter(Writer r) | 把基本流变成高级流 |
原理:底层自带了长度为8192的缓冲区提高性能。
特有方法
字符缓冲输入流特有方法 | 说明 |
---|---|
public String readLine() | 读取一行数据,如果没有数据可读了,会返回null |
细节:readLine方法在读取的时候,一次读一整行,遇到回车换行结束,但是他不会把回车换行读到内存当中。
字符缓冲输出流特有方法 | 说明 |
---|---|
public void newLine() | 跨平台的换行 |
总结
-
缓冲流有几种?
-
字节缓冲输入流:BufferedInputStream
-
字节缓冲输出流:BufferedOutputStream
-
字符缓冲输入流:BufferedReader
-
字符缓冲输出流:BufferedWriter
-
-
缓冲流为什么能提高性能
-
缓冲流自带长度为8192的缓冲区
-
可以显著提高字节流的读写性能
-
对于字符流提到不明显,对于字符缓冲而言关键点是两个特有的方法
-
-
字符缓冲流两个特有的方法是什么?
-
字符缓冲输入流BufferedReader:readLine()
-
字节缓冲输出流BufferedWriter:newLine()
-
转换流
转换流是字符流和字节流之间的桥梁。可以根据字符集一次读取多个字节,读取数据不会乱码了。
作用1:指定字符集读写
作用2:字节流想要使用字符流中的方法
转换流读取
jdk11之前的:
//1、创建对象并指定字符编码
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\Code\myio\myIo\a.txt"),"GBK");
//2、读取数据
int ch;
while((ch = isr.read()) != -1){
System.out.print((char)ch);
}
//3、释放资源
isr.close();
jdk11之后(包含jdk11)
//1、创建对象并指定字符编码
FileReader fr = new FileReader("D:\Code\myio\myIo\c.txt",Charset.forName("GBK"));
//2、读取数据
int ch;
while((ch = isr.read()) != -1){
System.out.print((char)ch);
}
//3、释放资源
isr.close();
转换流写出
jdk11之前的:
//1、创建转换流的对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\Code\myio\myIo\b.txt"),"GBK");
//2、写出数据
osw.write("你好你好");
//3、释放资源
osw.close();
jdk11之后(包含jdk11)
FileWriter fw = new FileWriter("D:\Code\myio\myIo\b.txt",Charset.forName("GBK"));
fw.writer("你好你好");
fw.close();
转换流读取+写出
jdk11之前的:
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\Code\myio\myIo\a.txt"),"GBK");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\Code\myio\myIo\b.txt"),"UTF-8");
int ch;
while((ch = isr.read()) != -1){
osw.write(ch);
}
osw.close();
isr.close();
jdk11之后(包含jdk11)
FileReader fr = new FileReader("D:\Code\myio\myIo\c.txt",Charset.forName("GBK"));
FileWriter fw = new FileWriter("D:\Code\myio\myIo\b.txt",Charset.forName("UTF-8"));
int b;
while((b = fr.read()) != -1){
fw.write(b);
}
fw.close();
fr.close();
转换流练习题
利用字节流读取文件中的数据,每次读一整行,而且不能出现乱码
-
字节流在读取中文的时候,是会出现乱码的,但是字符流可以搞定
-
字节流里面是没有读一整行的方法的,只有字符缓冲才能搞定
//复杂
FileInputStream fis = new FileInputStream("D:\Code\myio\myIo\a.txt");
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
String str = br.readLine();
System.out.println(str);
br.close();
//简化(并加上查询文件所有内容)
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("D:\Code\myio\myIo\a.txt")));
String line;
while((line = br.readLine() != null)){
System.out.println(line);
}
br.close();
总结
-
转换流的名字是什么?
-
字符转换输入流:InputStreamReader
-
字符转换输出流:OutputStreamWriter
-
-
转换流的作用是什么?
-
指定字符集读写数据(JDK11之后已淘汰)
-
字节流想要使用字符流中的方法了
-
序列化
序列化流
序列化流可以把Java中的对象写道本地文件中
构造方法 | 说明 |
---|---|
public ObjectOutputStream(OutputStream out) | 把基本流包装成高级流 |
成员方法 | 说明 |
---|---|
public final void writeObject(Object obj) | 把对象序列化(写出)到文件中区 |
细节:
使用对象输出流将对象保存到文件时会出现NotSerializableException异常
解决方案:需要让Javabean类实现Serializable接口
Serializable接口里面是没有抽象方法,标记型接口
一旦实现了这个接口,那么就表示当前的Student类可以被序列化
理解:一个物品的合格证
案例:
//1、创建对象(创建一个对象的类)
Student stu = new Student("zhangsan",23)
//2、创建序列化流的对象/对象操作输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\Code\myio\myIo\a.txt"))
//3、写出数据
oos.writeObject(stu);
//4、释放数据
oos.close();
反序列化流
反序列化流/对象操作输入流可以把序列化到本地文件中的对象,读取到程序中来
构造方法 | 说明 |
---|---|
public ObjectInputStream(InputStream out) | 基本流变成高级流 |
成员方法 | 说明 |
---|---|
public Object readObject() | 把序列化到本地文件中的对象,读取到程序中来 |
案例:
//1、创建反序列化流的对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\Code\myio\myIo\a.txt"))
//2、读取数据
Object o = ois.readObject();
//如果非要用student : Student o = (Student) ois.readObject();
//3、打印对象
System.out.println(o);
//4、释放资源
ois.close();
细节汇总:
-
使用序列化流将对象写到文件时,需要让javabean类实现Serializable接口。
否则,会出现NotSerializableException异常
-
序列化流写到文件中的数据是不能修改的,一旦修改就无法再次都回来。
-
序列化对象后,修改了Javabean类,再次反序列化,会不会有问题?
会出现问题,会抛出InvalidClassException异常
解决方案:给Javabean类添加serialVersionUID(序列号、版本号)
//代码编写(也可以直接在idea中的设置查找serialVersionUID进行定义,用快捷方式编写出来) private static final long serialVersionUID = 1L; //private:当前类的私有 , static:表示这个类都共享同一个版本号 , final:表示最终,表示版本号的值永远不会发生变化 , Long版本号比较长所以用long 版本号:serialVersionUID单词是固定的;
-
如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?
解决方案:给该成员变量加trasient关键字修饰,该关键字标记的成员变量不参与序列化过程
//trasient:瞬态关键字
//作用:不会把当前属性序列化到本地文件当中
private transient String address;
打印流
字节打印流
分类:打印流一般是指:PrintStream,PrintWriter两个类。
-
特点1:打印流只操作文件目的地,不操作数据源
-
特点2:特有的写出方法可以实现,数据原样写出
-
例如:打印:97 文件中:97
-
打印:true 文件中:true
-
特点3:特有的写出方法,可以实现自动刷新,自动换行
-
打印一次数据 = 写出 + 换行 + 刷新
-
构造方法 | 说明 |
---|---|
public PrintStream(OutputStream/File/String) | 关联字节输出流/文件/文件路径 |
public PrintStream(String fileName, Charset charset) | 指定字符编码 |
public PrintStream(OutputStream out, boolean autoFlush) | 自动刷新 |
public PrintStream(OutputStream out, boolean autoFlush, String encoding) | 指定字符编码且自动刷新 |
-
字节流底层没有缓冲区,开不开自动刷新都一样。
成员方法 | 说明 |
---|---|
public void write(int b) | 常规方法:规则跟之前一样,指定的字节写出 |
public void println(Xxx xx) | 特有方法:打印任意数据,自动刷新,自动换行 |
public void print(Xxx xx) | 特有方法:打印任意数据,不换行 |
public void printf(String format , Object... args) | 特有方法:带有占位符的打印语句,不换行 |
案例:
//1、创建字节打印流的对象
PrintStream ps = new PrintStream(new FileOutputStream("D:\Code\myio\myIo\a.txt"),true,Charset.forName("UTF-8"))
//2、写出数据
ps.println(97);//写出 + 自动刷新 + 自动换行
ps.print(true);
//3、释放数据
ps.close();
字符打印流
构造方法 | 说明 |
---|---|
public PrintWriter(Writer/File/String) | 关联字节输出流/文件/文件路径 |
public PrintWriter(String fileName, Charset charset) | 指定字符编码 |
public PrintWriter(Writer w, boolean autoFlush) | 自动刷新 |
public PrintWriter(OutputStream out, boolean autoFlush, Charset charset) | 指定字符编码且自动刷新 |
-
字符流底层有缓冲区,想要自动刷新需要开启
成员方法 | 说明 |
---|---|
public void write( . . . ) | 常规方法:规则跟之前一样,写出字节或者字符串 |
public void println(Xxx xx) | 特有方法:打印任意类型的数据并且换行 |
public void print(Xxx xx) | 特有方法:打印任意类型的数据,不换行 |
public void printf(String format , Object... args) | 特有方法:带有占位符的打印语句 |
案例:
//1、创建字符打印流的对象
PrintWriter pw = new PrintWriter(new FileWriter("D:\Code\myio\myIo\a.txt"),true);
//2、写出数据
pw.println("大会警告和高山大海公司");
pw.print("和嘎哈地方");
pw.printf("%s爱上了%s","阿珍","阿强")
//3、释放数据
pw.close();
打印流应用场景
//获取打印流的对象,此打印流在虚拟机启动的时候,由虚拟机创建,默认指向控制台
//特殊的打印流,系统中的标准输出流,是不能关闭,在系统中是唯一的。
PrintStream ps = System.out;
//调用打印流中的方法println
//写出数据,自动换行,自动刷新
ps.println("123");
//ps.close();
ps.println("就爱看的风格就爱看");
System.out.println("456");
总结:
-
打印流有几种?各有什么特点?
-
有字节打印流和字符打印流两种
-
打印流不操作数据源,只有操作目的地
-
字节打印流:默认自动刷新,特有的println自动换行
-
字符打印流:自动刷新需要开启,特有的println自动换行
-
压缩流
解压缩流
解压本质:把每一个ZipEntry按照层级拷贝到本地另一个文件夹中
案例:
public class ZipStreamDemo1{
public static void main(String[] args){
//1、创建一个File表示要解压的压缩包
File src = new File("D:\\aaa.zip");
//2、创建一个File表示解压的目的地
File dest = new File("D:\\");
unzip(src,dest);
}
//定义一个方法用来解压
public static void unzip(File src , File dest) throws IOException{
//解压的本质:把压缩包里面的每一个文件夹读取出来,按照层级拷贝到目的地当中
//创建一个解压缩流用来读取压缩包中的数据
ZipInputStream zip = new ZipInputStream(new FileInputStream(src));
//要先获取到压缩包里面的每一个zipentry对象
//表示当前在压缩包中获取到的文件或者文件夹
ZipEntry entry;
While((entry = zip.getNextEntry()) != null){
System.out.println(entry);
if(entry.isDirectory()){
//文件夹:需要在目的地dest处创建一个同样的文件夹
File file = new File(dest,entry.toString());
file.mkdirs();
}else{
//文件:需要读取到压缩包中的文件,并把它存放到目的地dest文件夹中(按照层级目录进行存放)
FileOutputStream fos = new FileOutputStream(new File(dest,entry.toString()));
int b;
while((b = zip.read()) != -1){
//写到目的地
fos.write(b);
}
fos.close();
//表示在压缩包中的一个文件处理完毕了。
zip.closeEntry();
}
}
zip.close();
}
}
压缩流
压缩本质:把每一个(文件/文件夹)看成ZipEntry对象放到压缩包中
压缩文件
public class ZipStreamDemo2{
public static void main(String[] args){
//1.创建File对象表示要压缩的文件
File src = new File("D:\\a.txt");
//2.创建File对象表示压缩包的位置
File dest = new File("D:\\");
//3.调用方法用来压缩
toZip(src,dest);
}
//作用:压缩
//参数一:表示要压缩的文件
//参数二:表示压缩包的位置
public static void toZip(File src , File dest) throws IOException{
//1、创建压缩流关联压缩包
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(dest,"a.zip")));
//2、创建ZipEntry对象,表示压缩包里面的每一个文件和文件夹
//参数:压缩包里面的路径
ZipEntry entry = new ZipEntry("aa\\dd\\a.txt");
//3、把ZipEntry对象放到压缩包当中
zos.putNextEntry(entry);
//4、把src文件中的数据写到压缩包当中
FileInputStream fis = new FileInputStream(src);
int b;
while((b = fis.read()) != -1){
zos.write(b);
}
//关闭entry
zos.closeEntry();
//关闭压缩流
zos.close();
}
}
压缩文件夹
public class ZipStreamDemo2{
public static void main(String[] args){
//1、创建File对象表示要压缩的文件夹
File src = new File("D:\\aaa");
//2、创建File对象表示压缩包放在哪里(压缩包的父级路径)
File destParent = src.getParentFile();
//3、创建File对象表示压缩包的路径
File dest = new File(destParent,src.getName() + ".zip");
//4、创建压缩流关联的压缩包
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest));
//5、获取src里面的每一个文件,变成ZipEntry对象,放入到压缩包当中
toZip(src,zos,src.getName());
//6、释放资源
zos.close();
}
//作用:获取src里面的每一个文件,变成ZipEntry对象,放入到压缩包当中
//参数一:数据源
//参数二:压缩流
//参数三:压缩包内部的路径
public static void toZip(File src,ZipOutputStream zos,String name) throws IOException{
//1、进入src文件夹
File[] files = src.listFiles();
//2、遍历数组
for(File file : files){
if(file.isFile()){
//3、判断-文件,变成ZipEntry对象,放入到压缩包当中
ZipEntry entry = new ZipEntry(name + "\\" + file.getName());
zos.putNextEntry(entry);
//读取文件中的数据,写到压缩包
FileInputStream fis = new FileInputStream(file);
int b;
while((b = fis.read()) != -1){
zos.write(b);
}
fis.close();
zos.closeEntry();
}else{
//4、判断-文件夹,递归
toZip(file,zos,name + "\\" + file.getName());
}
}
}
}
常用工具包
Commons-io
Commons-io是apache开源基金组织提供的一组有关IO操作的开源工具包。
作用:提高IO流的开发效率
使用步骤:
-
在项目中创建一个文件夹:lib
-
将jar包复制粘贴到lib文件夹
-
右键点击jar包,选择Add as Library -> 点击OK
-
在类中导包使用
FileUtils类(文件/文件夹相关) | 说明 |
---|---|
static void copyFile(File srcFile , File destFile) | 复制文件 |
static void copyDirectory(File srcDir , File destDir) | 复制文件夹 |
static void copyDirectoryToDirectory(File srcDir , File destDir) | 复制文件夹 |
static void deleteDirectory(File directory) | 删除文件夹 |
static void cleanDirectory(File directory) | 清空文件夹 |
static String readFileToString(File file , Charset encoding) | 读取文件中的数据变成成字符串 |
static void write(File file , CharSepuence data , String encoding) | 写出数据 |
IOUtils类(流相关相关) | 说明 |
---|---|
public static int copy(InputStream input , OutputStream output) | 复制文件 |
public static int copyLarge(Reader input , Writer output) | 复制大文件 |
public static String readLines(Reader input) | 读取数据 |
public static void write(String data , OutputStream output) | 写出数据 |
部分方法案例
public class ZipStreamDemo{
public static void main(String[] args){
//复制文件
File src = new File("D:\\aaa.txt");
File dest = new File("D:\\bbb.txt");
FileUtils.copyFile(src,dest);
//复制文件夹(这个复制是包含了aaa文件夹的复制)
File src = new File("D:\\aaa");
File dest = new File("D:\\bbb");
FileUtils.copyDirectoryToDirectory(src,dest);
//复制文件夹(这个复制是不包含了aaa文件夹的复制)
File src = new File("D:\\aaa");
File dest = new File("D:\\bbb");
FileUtils.copyDirectory(src,dest);
//删除文件夹(包含bbb文件夹的删除)
File dest = new File("D:\\bbb");
FileUtils.deleteDirectory(dest);
//清空文件夹(不包含bbb文件夹的清空)
File dest = new File("D:\\bbb");
FileUtils.cleanDirectory(dest);
}
}
Hutool
相关类 | 说明 |
---|---|
IoUtil | 流操作工具类 |
FileUtil | 文件读写和操作的工具类 |
FileTypeUtil | 文件类型判断工具类 |
WatchMonitor | 目录、文件监听 |
ClassPathResource | 针对ClassPath中资源的访问封装 |
FileReader | 封装文件读取 |
FileWriter | 封装文件写入 |
//file:根据参数创建一个file对象
//touch:根据参数创建文件
//writeLines:把集合中的数据写出到文件中,覆盖模式。
//appendLines:把集合中的数据写出到文件中,续写模式。
//readLines:指定字符编码,把文件中的数据,读到集合中。
//readUtf8Lines:按照UTF-8的形式,把文件中的数据,读到集合中
//copy:拷贝文件或是文件夹
//根据参数创建一个file对象
File touch = FileUtil.file("D:\\" , "aaa" , "bbb" , "a.txt");
System.out.println(files1);
//根据参数创建文件(即使没有根文件也能把根文件创建出来)
File touch = FileUtil.touch(file1);
System.out.println(touch);
//把集合中的数据写出到文件中,覆盖模式。
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa");
File file2 = FileUtil.writeLines(list,"D:\\a.txt","UTF-8");
System.out.println(file2);
//把集合中的数据写出到文件中,续写模式。
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa");
File file3 = FileUtil.appendLines(list,"D:\\a.txt","UTF-8");
System.out.println(file3);
//指定字符编码,把文件中的数据,读到集合中。
List<String> list = FileUtil.readLines("D:\\a.txt","UTF-8");
System.out.println(list)