Java – IO流 – FileWriter字符输出流
简介
FileWriter 是 IO流体系中的字符输出OutputStream的子类,负责 字符流的输出操作,可以把程序中的数据写到本地文本文件中。
创建输出流
输出流总体的操作步骤有三步:
1.创建字符输出流对象
2.写出数据
3.释放资源
创建对象
创建对象构造方法时,可以传递字符串形式的文件绝对或相对地址,也可以创建一个 File 对象并传入。
// 以字符串形式的绝对或相对路径创建字节流对象,默认清空文件内容再写
public FileWriter(String name);
// 是否追加内容式写入数据(数据续写)
public FileWriter(String name , boolean append)
// 以File对象形式创建字符流对象,默认清空文件内容再写
public FileWriter(File name);
// 是否追加内容式写入数据(数据续写)
public FileWriter(File name , boolean append)
// JDK11 后提供了自定义字符编码写出文件流
public FileWriter(File name , Charset charName)
public FileWriter(File name , Charset charName, boolean append)
注意:
1.参数是字符串表示的路径或者是File对象都可以的
2.如果文件不存在会创建一个新的文件,但是要保证父级文件夹路径是存在的,否则会报出异常
3.如果文件已经存在,则会清空文件,除非调用带有 append 参数的构造函数。
写出数据
// 通过写入单个字符的数据到文件中,int 型参数表示要传入的数据为字符对应的字符集码
public void write(int c);
// 通过写入一串字符串数据到文件中
public void write(String str);
// 可以指定这个 字符串 写入的索引和长度
public void write(String str, int off, int len)
// 通过写入字符数组的方式到文件中
public void write(char c[])
// 可以指定这个 char 数组写入的索引和长度
public void write(char c[], int off, int len);
注意:
1.wirte方法的参数是整数,但是实际上写到本地文件中的是整数在字符集上对应的字符。
2.FileWriter 中的 write 和 FileOutputStream 中的 write 的区别在于,FileWriter 会根据字符个数来写入字节数,如果一个字符的存储量是3个字节,那么使用FileWriter 的 write 写入一个字符将被写入3字节,而 FileOutputStream 中的 write 永远只写出1个字节。
释放资源
Java在写文件的时候,会对文件进行占用锁定,期间其它程序无法对它进行操作,因此我们对文件操作完成后,应该要对文件进行解锁去除占用。
fw.close();
异常中的处理(普通方式)
中,包含了编译时异常,如果调用FileWriter
创建构造时,会出现编译错误,需要我们 FileWriter
throws
抛出异常。
同时也可以使用 try...catch
的方式进行处理。
但是 try...catch
中存在两个问题:
问题一:
找不到文件时会直接抛出异常,FileWriter
try
中一旦出现异常时,会停止执行 try
下面的代码,这使得 close()
关闭流这种方法有可能没有执行到。
try {
// 如果 FileWriter 出现异常,后面的代码不会执行
FileWriter fw = new FileWriter ("不存在的文件");
// 这里的代码不会被执行,所以 fw.close() 也不会被执行
fw.close();
}catch (IOException e){
e.printStackTrace();
}finally {
// 如果把 fw.close() 放在这里,则因为作用域的原因,会找不到 fw 对象
fw.close();
}
解决方法是,把
创建对象移出 FileWriter
try
作用域外
// 把 FileWriter 创建对象移出作用域名,必须初始化为 null,否则 finally 处的 fw.close 会报编译错误
// 原因是,未初始化的对象不能调用 任何 方法
FileWriter fw = null;
try {
// 但因 FileWriter 本身也有编译异常,所以不能在 try 外面 new
fw = new FileWriter("不存在的文件");
// 这里的代码不会被执行,所以 fw.close() 也不会被执行
fw.close();
}catch (IOException e){
e.printStackTrace();
}finally {
// 如果把 fw.close() 放在这里,则因为作用域的原因,会找不到 fw 对象
fw.close();
}
问题二:假如,try
中的
创建依然报错,那么 fw 对象依然是FileWriter
null
,这时调用 finally
代码块中的 fw.close()
时,依然会报错
// 把 FileWriter 创建对象移出作用域名
FileWriter fw = null;
try {
// 但因 FileWriter 本身也有编译异常,所以不能在 try 外面 new
fw = new FileWriter("不存在的文件");
// 这里的代码不会被执行,所以 fw.close() 也不会被执行
fw.close();
}catch (IOException e){
e.printStackTrace();
}finally {
if (fw != null){
fw.close();
}
}
解决方法是:在 调用 close()
方法之前,判断 fw 是否为 null
异常中的处理(JDK7方式)
Java 也发现了普通方法中处理 close()
是比较麻烦的,所以在JDK 7 后,提供一个自动关闭文件接口 AutoCloseable
方法,
实现了 FileWriter
AutoCloseable
接口,我们不需要手动去调用 close()
方法
用法如下
try(定义字节流1; 定义字节流2) {
fw... 处理逻辑
fw2... 处理逻辑
}catch (IOException e){
}
在JDK7中,try
多出一个小括号,括号中编写定义字节流的方法,多个字节流定义,使用;
进行分割即可。
try(FileWriter fw = new FileWriter("不存在的路径");
FileWriter fw2 = new FileWriter("不存在的路径")) {
fw... 处理逻辑
fw2... 处理逻辑
}catch (IOException e){
}
不需要调用 close()
方法
异常中的处理(JDK9方式)
从JDK7的方案来看,确实比较好,但是在 try()
中传入创建方法,使得代码非常长,不利于阅读,在JDK9 中,Java 允许创建方法在try()
代码块外面定义,try()
中传个对象即可。
FileWriter fw = new FileWriter("不存在的路径");
FileWriter fw2 = new FileWriter("不存在的路径");
try(fw; fw2) {
fw... 处理逻辑
fw2... 处理逻辑
}catch (IOException e){
}
多个对象,依然使用 ;
分割即可。
FileWriter底层原理
1.当创建FileWriter对象时,对象内部会生成一个 byte[8192] 的数组。
2.当调用第一次 write() 方法时,FileWriter 会往 byte[8192] 数组中填入数据。
3.当 byte[8192] 数组被填满后,FileWriter 会把数组中的数据写出到文本文件中,当再次写数据时,不会马上写到文件中,而是再一次存放到 byte[] 数组中。
4.或当填入数据后(数组未被填满的情况下),调用 flush() 刷新方法,FileWriter 会立即把数据写到文件中,flush() 方法只负责把数据即时写到文本文件中,不会关闭文件流。
5.当 close() 方法被调用后,FileWriter 也会把仅存在的 byte[] 中剩下的数据写出到文本文件中,并关闭文件流。
注意:FileOutputStream 中的 write() 不具有 byte[] 数据缓冲机制。
换行与续写
换行
在不同的操作系统中,换行符也不一样
1.Windows 中的换行符为 \r\n
2.Linux 中的换行符为 \n
3.MacOS 中的换行符为 \r
在Java中,换行符的问题已经做了优化补全,所以即使使用 \n
也可以实现换行
String wrap = "\r\n";
fw.write(wrap.getBytes());
fw.write("\r\n"); // 直接使用字符串
续写
FileWriter 在创建对象中,包含了续写的构造函数
FileWriter fw = new FileWriter("path", true);
共有 0 条评论