该文章Github地址:https://github.com/AntonyCheng/java-notes【有条件的情况下推荐直接访问GitHub以获取最新的代码更新】
在此介绍一下作者开源的SpringBoot项目初始化模板(Github仓库地址:https://github.com/AntonyCheng/spring-boot-init-template【有条件的情况下推荐直接访问GitHub以获取最新的代码更新】& CSDN文章地址:https://blog.csdn.net/AntonyCheng/article/details/136555245),该模板集成了最常见的开发组件,同时基于修改配置文件实现组件的装载,除了这些,模板中还有非常丰富的整合示例,同时单体架构也非常适合SpringBoot框架入门,如果觉得有意义或者有帮助,欢迎Star & Issues & PR!
上一章:由浅到深认识Java语言(36):I/O流
44.I/O流(操作文件中的数据)
字符流
只能操作文本文件;
字符流 = 字节流 + 编码表
Writer类
是所有字符输出流的超类(写入文本文件);
- write(int c) 写入单个字符;
- write(char[] ch) 写入字符数组;
- write(char[] ch,int off,int len) 写入字符数组一部分,开始索引以及写入的个数;
- write(String str) 写入字符串;
- flush() 刷新该流的缓冲(该类写入数据时先写入内存,只能刷新了数据才会抵达目的路径),而在 close() 方法完成后也会自动调用一次 flush() 方法,但是建议手动刷新,防止内存积压过多;
OutputStreamWriter 实现类
OutputStreamWriter 实现类继承 Writer 类,是字符的输出流,同时也被称作转换流,这个类也是“装饰者”,装饰输出流(OutputStream);
转换流:把字符流转换成字节流;
构造方法:
- OutputStreamWriter(OutputStream out) 传递任意字节输出流;
- OutputStreamWriter(OutputStream out,String 编码表名) 传递任意字节输出流,编码表名,不同的 IDE 有不同的默认编码表,IDEA 是 UTF-8 ,eclipse 是 GBK;
使用类示例如下:
package top.sharehome.Demo;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class Demo {
public static void main(String[] args) {
FileOutputStream fos = null;
OutputStreamWriter osw = null;
try {
fos = new FileOutputStream("d:\\大学课程学习文档\\java\\Practice\\IO\\test1.txt");
osw = new OutputStreamWriter(fos, "utf8");
osw.write("啦啦啦啦啦啦");
osw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (osw != null) {
osw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
打印效果如下:
Reader类
是所有字符输入流的超类(读取文本文件);
- int read() 读取单个字符;
- int read(char[] ch) 读取字符数组;
InputStreamReader 实现类
InputStreamWriter 实现类继承 Reader 类,是字符的输入流,同时也被称作转换流,这个类也是“装饰者”,装饰输入流(InputStream);
转换流:字节流转成字符流;
构造方法:
- InputStreamReader(InputStream in) 传递任意字节输入流;
- InputStreamReader(InputStream in,String 编码表名) 传递任意字节输入流,编码表名,不同的 IDE 有不同的默认编码表,IDEA 是 UTF-8 ,eclipse 是 GBK;
使用类示例如下:(test2.txt 文件如下)
package top.sharehome.Demo;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class Demo {
public static void main(String[] args) {
FileInputStream fis = null;
InputStreamReader isr = null;
try {
fis = new FileInputStream("d:\\大学课程学习文档\\java\\Practice\\IO\\test2.txt");
isr = new InputStreamReader(fis);
char[] ch = new char[1024];
int flag = 0;
while ((flag=isr.read(ch)) != -1) {
System.out.println(new String(ch, 0, flag));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (isr != null) {
isr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
打印效果如下:
便捷类
-
FileWriter 继承自 OutputStreamWriter;
- 字符的输出流,写入文本文件;
- 直接采用默认的编码表(utf-8);
- FileWriter 构造方法直接传递字符串的文件名即可,该文件若在项目根路径不存在,则在根路径创建后再写入;
示例如下:
package top.sharehome.Demo; import java.io.FileWriter; import java.io.IOException; public class Demo { public static void main(String[] args) { FileWriter fw = null; try { fw = new FileWriter("d:\\大学课程学习文档\\java\\Practice\\IO\\test2.txt"); fw.write("你好 IO流"); fw.flush(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (fw != null) { fw.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
打印效果如下:
-
FileReader 继承自 InputStreamReader;
- 字符的输入流,读取文本文件;
- 直接采用默认的编码表;
- FileReader 构造方法直接传递字符串的文件名即可,必须要有数据源文件;
示例如下:
package top.sharehome.Demo; import java.io.FileReader; import java.io.IOException; public class Demo { public static void main(String[] args) { FileReader fr = null; try { fr = new FileReader("d:\\大学课程学习文档\\java\\Practice\\IO\\test2.txt"); char[] ch = new char[1024]; int flag = 0; while ((flag = fr.read(ch)) != -1) { System.out.print(new String(ch,0,flag)); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (fr != null) { fr.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
打印效果如下:
字符流的缓冲流
使用字符流的缓冲流,提高原有流对象的读写性能;
字符流的缓冲流是字符流中便捷类的**“装饰者”**;
-
BufferedWriter 继承自 Writer;
-
字符输出流的缓冲流,写入文本文件;
-
特殊方法:newLine() 写入文本换行符,由于每个操作系统的换行符不一样,这个方法就实现了代码的跨平台性;
示例如下:
package top.sharehome.Demo; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; public class Demo { public static void main(String[] args) { FileWriter fr = null; BufferedWriter bf = null; try { fr = new FileWriter("d:\\大学课程学习文档\\java\\Practice\\IO\\test1.txt"); bf = new BufferedWriter(fr); bf.write(97); bf.newLine(); bf.write(98); bf.flush(); }catch (IOException e){ e.printStackTrace(); }finally { try { if (fr!=null){ fr.close(); } }catch (IOException e){ e.printStackTrace(); } } } }
打印效果如下:
-
-
BufferedReader 继承自 Reader;
- 字符输入流的缓冲流,读取文本文件;
- 特殊方法:readLine() 读取文本一行,由于每个操作系统的换行符不一样,这个方法就实现了代码的跨平台性,返回 String ,当读取完文件后反 null;
示例如下:
package top.sharehome.Demo; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class Demo { public static void main(String[] args) { FileReader fr = null; BufferedReader br = null; try { fr = new FileReader("d:\\大学课程学习文档\\java\\Practice\\IO\\test1.txt"); br = new BufferedReader(fr); String flag = null; while ((flag = br.readLine()) != null) { System.out.println("flag = " + flag); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (br != null) { br.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
打印效果如下:
字符流的缓冲流和字节流的缓冲流使用方法大致相同;
在 Java11 之后可以使用一种更简单的方法来读取一个文件(类似于迭代器的遍历方式),此时要用Scanner类来获取一个文件:
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Scanner;
/**
* @author AntonyCheng
* @date 2022/8/28 17:32
*/
public class Demo {
public static void main(String[] args) {
Scanner in = null;
try {
//Scanner(Path source, Charset charset)构造器需要Java10
//Path接口中Path of(String first, String... more)需要Java11
in = new Scanner(Path.of("d:\\desktop\\txt.png"), StandardCharsets.UTF_8);
while (in.hasNextLine()) {
System.out.println(in.nextLine());
}
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
} finally {
if (in != null) {
in.close();
}
}
}
}
BufferedWriter 构造方法
new BufferedWriter(Writer w)
传递字符输出流;
BufferedReader 构造方法
new BufferedReader(Reader r)
传递字符输入流;
禁止使用字符流复制文本文件
这是一个错误的应用,不能保证复制后和源文件是一致的;
打印流
-
PrintStream:字节输出流;
-
PrintWriter:字符输出流;
-
打印流特性:
-
打印流负责输出打印,不关心数据源;
-
方便地打印各种形式数据;
-
打印流永远不会抛出 IO 异常;
-
具有自动刷新的功能;
即添加参数 true ,但是要注意自动刷新必须需要 println 或者 printf 或者 format 进行打印
-
这些依然是**“装饰者”**,需要再构造方法中引入字节流或者字符流;
-
打印流示例如下:
-
PrintStream 示例:
package top.sharehome.Demo; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; public class Demo { public static void main(String[] args) { FileOutputStream fos = null; PrintStream ps = null; try { fos = new FileOutputStream("d:\\大学课程学习文档\\java\\Practice\\IO\\test1.txt"); ps = new PrintStream(fos); ps.print("这里写什么就会在文件里写什么!"); } catch (IOException e) { e.printStackTrace(); } finally { if (ps != null) { ps.close(); } } } }
打印效果如下:
-
PrintWriter 示例:
package top.sharehome.Demo; import java.io.*; public class Demo { public static void main(String[] args) { FileWriter fw = null; PrintWriter pw = null; try { fw = new FileWriter("d:\\大学课程学习文档\\java\\Practice\\IO\\test1.txt"); pw = new PrintWriter(fw); pw.println("这里写什么就会在文件里写什么!"); } catch (IOException e) { e.printStackTrace(); } finally { if (pw != null) { pw.close(); } } } }
打印效果如下:
基本数据流
-
DataInputStream
- 基本数据类型读取流;
- 构造方法传递一个字节输入流;
-
DataOutputStream
- 基本数据类型写入流;
- 构造方法传递一个字节输出流;
-
基本数据流依然是一个**“装饰者”**;
基本数据流示例如下:
package top.sharehome.Demo;
import java.io.*;
public class Demo {
public static void main(String[] args) {
FileOutputStream fos = null;
DataOutputStream dos = null;
FileInputStream fis = null;
DataInputStream dis = null;
try {
fos = new FileOutputStream("d:\\大学课程学习文档\\java\\Practice\\IO\\test1.txt");
dos = new DataOutputStream(fos);
fis = new FileInputStream("d:\\大学课程学习文档\\java\\Practice\\IO\\test1.txt");
dis = new DataInputStream(fis);
dos.writeInt(6);
int i = dis.readInt(); //这里不能使用普通的 read() 方法,需要和写入格式相统一
System.out.println("i = " + i);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (dos != null) {
dos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (dis != null) {
dis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
打印效果如下:
如果我们要连续写入读取多个值呢?首先想到的是循环,但是循环条件成了一个问题,因为这里传输的是基本数据类型,返回 -1 是有可能的,所以这里只能通过抓取异常来来确定循环结束点;
示例如下:
package top.sharehome.Demo;
import java.io.*;
public class Demo {
public static void main(String[] args) {
FileInputStream fis = null;
DataInputStream dis = null;
try {
fis = new FileInputStream("d:\\大学课程学习文档\\java\\Practice\\IO\\test1.txt");
dis = new DataInputStream(fis);
while (true){
try {
int readInt = dis.readInt();
System.out.println("readInt = " + readInt);
}catch (IOException e){
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (dis != null) {
dis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
打印效果如下: