目录
3.1 FileInputStream 和 FileOutStream
1. File类
1.1 介绍
Java文件类以抽象的方式代表文件名和目录路径名。该类主要用于文件和目录的创建、文件的查找和文件的删除等。
1.2 创建文件对象
创建文件的对象既可以时一个确切的文件(.txt、.doc、.word 等文件),也可以是目录(d:/aaa/bbb/ccc)。
//1. 通过给定的父抽象路径名和子路径名字符串创建一个新的File实例。
//File(File parent, String child);
File file1 = new File(new File("d:/temp"),"aaa/a.txt");
//2. 通过将给定路径名字符串转换成抽象路径名来创建一个新 File 实例。
//File(String pathname)
File file2 = new File("d:/temp/aaa/a.txt");
//3.根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
//File(String parent, String child)
File file3 = new File("d:/temp/aaa", "bbb/a.txt");
//4. 通过将给定的 file: URI 转换成一个抽象路径名来创建一个新的 File 实例。
//File(URI uri)
File file4 = new File(new URI("file:/d:/temp/a.txt"));
1.3 常用的文件操作
File file1 = new File("d:/AAA/aaa.txt"); //创建file对象
file1.createNewFile(); // 创建文件
File file2 = new File("d:/AAA/bbb");
file2.mkdir(); //创建单级目录
file2.deleteOnExit(); //程序退出时删除
File file3 = new File("d:/AAA/ccc/ddd");
file3.mkdirs();//创建多级目录
file3.delete();//删除
//先创建文件对象
File file = new File("d:/AAA/a.txt");
//调用相应的方法,得到对应信息
System.out.println("文件名字=" + file.getName());
//getName、getAbsolutePath、getParent、length、exists、isFile、isDirectory
System.out.println("文件绝对路径=" + file.getAbsolutePath());
System.out.println("文件父级目录=" + file.getParent());
System.out.println("文件大小(字节)=" + file.length());
System.out.println("文件是否存在=" + file.exists());
System.out.println("是不是一个文件=" + file.isFile());
System.out.println("是不是一个目录=" + file.isDirectory());
2. IO 流原理及流分类
2.1 IO 流原理
Java程序中,对于数据的输入/输出操作都是以“流(Stream)”的方式进行,I / O 是 Input / Output 的缩写,是非常实用的技术,用于处理数据传输,如读 / 写 文件,网络通讯等。(输入和输出相对程序来说,输入是把程序外的数据读入到程序中,输出是把数据从程序写出到指定位置)
Java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。Java.io 包中的流支持很多种格式,比如:基本类型、对象、本地化字符集等等。一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。
2.2 流的分类
1. 按操作的数据单位不同分为:字节流(8 bit)二进制文件,字符流(按字符)文本文件
使用前须知:由于字节流是一个字节一个字节的读取,utf-8编码中一个英文字符占用一个字节,因此使用字节流读取英文文件不会出现乱码,但是中文占用3个字节,所以可能出现乱码,又因为用字符流操作二进制文件可能会造成文件损坏,因此一般对于文本文件使用字符流操作,对于字节流文件(音频,视频)使用字节流操作
2. 按数据流的流向不同分为:输入流/输出流
3. 按流的角色不同分为: 节点流,处理流(包装流)
3. 常用的类
3.1 FileInputStream 和 FileOutStream
//创建FileInputStream对象
FileInputStream fileInputStream = new FileInputStream("d:/temp/a.txt");
//字节数组用与存储数据
byte[] bytes = new byte[8]; //数组长度可指定
//记录每次读取的实际长度
int readlen = 0;
//对文件循环读取 read(),会返回一个数字表示读取的长度,如果没有返回-1
while((readlen = fileInputStream.read(bytes)) != -1){
//以字符串的形式输出到控制台
//实际读取多少就输出多少,readlen 为实际读取长度
//如果没有控制长度的readlen 有可能会错误
//假设文本里面的数据为 Hello, world!
//而你顶的数组长度为[5]
//第一次读取['H','e','l','l','o']
//第二次读取[',','w','o','r','l']
//第三次读取后数组变为:['d','!','o','r','l']
//因为第三次就读取了两个 'd' 和 '!',所以后面的数据不会改变
//如果没有确定实际读取长度,那么后面的也会输出
//后面不在解释
System.out.print(new String(bytes,0,readlen));
}
//关闭流
fileInputStream.close();
FileOutputStream fileOutputStream = new FileOutputStream("d:/temp/b.txt");
String s = "Hello, lcy!";
fileOutputStream.write(s.getBytes(),0,s.getBytes().length);
fileOutputStream.close();
//FileInputStream与FileOutputStream结合实现音频文件拷贝
FileInputStream fileInputStream = new FileInputStream("d:/temp/CelloFox.flac");
FileOutputStream fileOutputStream = new FileOutputStream("d:/temp/CelloFox2.flac");
byte[] buf = new byte[1024];
int readlen = 0;
while((readlen = fileInputStream.read(buf)) != -1){
fileOutputStream.write(buf,0,readlen);
}
fileInputStream.close();
fileOutputStream.close();
3.2 FileReader 和 FileWriter
//创建 FileReader 对象
FileReader fileReader = new FileReader("d:/temp/a.txt");
//使用 char 数组 存储读取的数据
char[] chars = new char[8];
//记录实际读取的长度
int readline = 0;
//对文本进行读取
while((readline = fileReader.read(chars)) != -1){
System.out.print(new String(chars, 0, readline));
}
fileReader.close();
//创建 FileWriter 对象
//public FileWriter(String fileName, boolean append)
//后面带有boolean 时,true代表追加,false 代表重新写入,原先的数据将会被覆盖
FileWriter fileWriter = new FileWriter("d:/temp/c.txt", true);
//直接使用 write() 写入
fileWriter.write("Hello, world");
//记得关闭流
fileWriter.close();
FileReader fileReader = new FileReader("d:/temp/a.txt");
FileWriter fileWriter = new FileWriter("d:/temp/f.txt");
char[] chars = new char[8];
//实际读取长度
int readlen = 0;
while((readlen = fileReader.read(chars)) != -1){
//读取后直接以字符串的形式写入
fileWriter.write(new String(chars,0,readlen));
}
fileReader.close();
fileWriter.close();
4. 处理流
根据流的角色分为 节点流 和 处理流,之前使用的都是节点流,现在介绍处理流:
处理流也叫包装流,是在已存在的流之上,为程序提供更强大的读写能力,也更加灵活
(性能提高,操作便捷)
节点流 和 处理流的区别和联系:
1. 节点流 是底层流,直接跟数据源相接
2. 处理流 包装 节点流,既可以消除不同节点流的实现差异,也可提供更方便的方法完成输入输出
3. 处理流 使用了修饰器设计模式,不会直接与数据源项链
5. 处理流常用类
5.1 缓冲流
字符缓冲流:BufferedReader 和 BufferedWriter
BufferedReader bufferedReader = new BufferedReader(new FileReader("d:/temp/a.txt"));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("d:/temp/a1.txt"));
char[] chars = new char[8];
int readlen = 0;
while((readlen = bufferedReader.read(chars)) != -1){
bufferedWriter.write(chars, 0, readlen);
}
bufferedReader.close();
bufferedWriter.close();
字节缓冲流:BufferedInputStream 和 BufferedOutputStream
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:/temp/CelloFox.flac"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:/temp/CelloFox1.flac"));
byte[] bytes = new byte[1024];
int readlen = 0;
while((readlen = bis.read(bytes)) != -1){
bos.write(bytes, 0, readlen);
}
bis.close();
bos.close();
5.2 对象流
对象流能够在保存数据的同时把数据的类型保存下来,比如保存 int 100,那么不仅仅保存了100这个数据,同时保存了 它的类型:int,再比如保存一个对象 Student s = new Student("小红", 18),那么在恢复时便知道是一个 Student 类型。
使用须知: 如果想把数据类型进行保存,那么这个数据类型需实现序列化
序列化 : 保存数据时,保存数据的值和数据类型
反序列化:恢复数据时,恢复数据的值和数据类型
如果需让某个对象能够支持序列化机制,必须让其类实现Serializable(此接口没有方法需实现类实现,常用) 或者 Externalizable
//序列化后,保存的文件格式,不是存文本,而是按照他的格式来保存
String filePath = "e:\\data.dat";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
//序列化数据到 e:\data.dat
oos.writeInt(100);// int -> Integer (实现了 Serializable)
oos.writeBoolean(true);// boolean -> Boolean (实现了 Serializable)
oos.writeChar('a');// char -> Character (实现了 Serializable)
oos.writeDouble(9.5);// double -> Double (实现了 Serializable)
oos.writeUTF("lcy");//String
//保存一个 dog 对象
oos.writeObject(new Dog("旺财", 10, "日本", "白色"));
oos.close();
System.out.println("数据保存完毕(序列化形式)");
// 1.创建流对象 对上面存储的数据进行读取
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src\\data.dat"));
// 2.读取, 注意顺序
System.out.println(ois.readInt());
System.out.println(ois.readBoolean());
System.out.println(ois.readChar());
System.out.println(ois.readDouble());
System.out.println(ois.readUTF());
System.out.println(ois.readObject());
System.out.println(ois.readObject());
System.out.println(ois.readObject());
// 3.关闭
ois.close();
System.out.println("以反序列化的方式读取(恢复)ok~");
注意:序列化对象时,默认里面的属性都要进行序列化(除了static 和 transient 修饰的成员),要求里面的属性也要实现序列化接口,序列化具备可继承性,某类实现了序列化,则他的子类默认实现了序列化。
5.3 转换流
InputStreamReader 和 OutputStreamWriter
1. InputStreamReader 是 Reader 的子类,可以将 InputStream 转换成 Reader
2. OutputStreamWriter 是 Writer 的子类,可以将 OutputStream 转换成Writer
3. 可以在使用转换流是指定编码格式(按照什么格式输入/按照什么格式输入(utf-8,gbk等))
String filePath = "d:/temp/a.txt";
//解读
//1. 把 FileInputStream 转成 InputStreamReader
//2. 指定编码 gbk
//InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), "gbk");
//3. 把 InputStreamReader 传入 BufferedReader
//BufferedReader br = new BufferedReader(isr);
//将 2 和 3 合在一起
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "gbk"));
//4. 读取
String s = br.readLine();
System.out.println("读取内容=" + s);
//5. 关闭外层流
br.close();
// 1.创建流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d:/temp/a.txt"), "gbk");
// 2.写入
osw.write("hello,lcy~");
// 3.关闭
osw.close();
System.out.println("保存成功~");
5.4 打印流
PrintStream 和 PrintWriter 打印流只有输出流,没有输入流
PrintStream out = System.out;
//在默认情况下,PrintStream 输出数据的位置是 标准输出,即显示器
/*
public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
*/
out.print("lcy, hello");
System.out.println();
//因为 print 底层使用的是 write , 所以我们可以直接调用 write 进行打印/输出
out.write("lcy,你好".getBytes());
System.out.println();
out.close();
//我们可以去修改打印流输出的位置/设备
//1. 输出修改成到 "d:/temp/a.txt"
//2. "lcy, hello" 就会输出到 d:/temp/a.txt
//3. public static void setOut(PrintStream out) {
// checkIO();
// setOut0(out); // native 方法,修改了 out
// }
System.setOut(new PrintStream("e:\\f1.txt"));
System.out.println("hello, lcy");
System.out.println();
//PrintWriter 的使用
//PrintWriter printWriter = new PrintWriter(System.out);
PrintWriter printWriter = new PrintWriter(new FileWriter("e:\\f2.txt"));
printWriter.print("hi, lcy");
System.out.println();
printWriter.close(); //flush + 关闭流, 才会将数据写入到文件