字符流
以字符为单位读写数据,专门用来处理文本文件(解决中文字符问题)
字符输入流 Reader
-
java.io.Reader:字符输入流,是字符输入流的最顶层的父类,定义了一些共性的成员方法,是一个抽象类
-
共性的成员方法:
- int read() 读取单个字符。
- int read(char[] cbuf) 将字符读入数组
- abstract void close() 关闭该流并释放与之关联的所有资源 -
实现子类:java.io.FileReader extends InputStreamReader extends Reader
FileReader:文件字符输入流-
作用:把硬盘文件中的数据以字符的方式读取到内存中
-
构造方法:
FileReader(String fileName)
FileReader(File file)- 参数:读取文件的数据源
- String fileName:文件的路径
- File file:文件 - FileReader构造方法的作用:
1 创建一个FileReader对象
2 会把FileReader对象指向要读取的文件
- 参数:读取文件的数据源
-
-
字符输入流的使用步骤:
1 创建FileReader对象,构造方法中绑定要读取的数据源
2 使用FileReader对象中的方法read读取文件
3 释放资源
public class demo06Reader {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("D:\\Eclipse\\workplace\\day1\\src\\num10\\d.txt");
//1 int read() 读取单个字符。
/*
int len = 0; //存储读取到的有效字符
while((len = fr.read())!=-1) {
System.out.println((char)len); //强转
}
*/
//一次读取多个字符int read(char[] cbuf)
int len = 0; //记录每次读取的有效读取个数
char[] cs = new char[1024]; //存储读取到的多个字符
while((len = fr.read(cs)) != -1) {
/*
String构造方法:
String(char[] value):把字符数组转换为字符串
String(char[] value,int offset,int count):把字符数组的一部分转换为字符串
*/
System.out.println(new String(cs,0,len)); //100你好abc
}
fr.close(); //释放资源
}
}
字符输出流 Writer
-
java.io.Writer:字符输出流,是所有字符输出流的最顶层的父类,是一个抽象类
-
共性的成员方法:
- void write(char[] cbuf) 写入字符数组。
- abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。
- void write(int c) 写入单个字符。
- void write(String str) 写入字符串。
- void write(String str, int off, int len) 写入字符串的某一部分
- abstract void close() 关闭此流,但要先刷新它。
- abstract void flush() 刷新该流的缓冲。 -
实现子类:java.io.FileWriter extends OutputStreamWriter extends Writer
FileWriter:文件字符输出流-
作用:把内存中字符数据写入到文件中
-
构造方法:
FileWriter(File file) 根据给定的 File 对象构造一个 FileWriter对象
FileWriter(String fileName) 根据给定的文件名构造一个 FileWriter对象- 参数:写入数据的目的地
File file:文件
String name:文件的路径 - 构造方法的作用:
1 会创建一个FileWriter对象
2 会根据构造方法中传递的文件/文件的路径,创建文件
3 会把FileWriter对象指向创建好的文件
- 参数:写入数据的目的地
-
-
字符输出流的使用步骤:
1 创建FileWriter对象,构造方法中绑定要写入数据的目的地
2 使用FileWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程,计算机是以字节存储的)
3 使用FileWriter中的方法flush,把内存缓冲区中的数据,刷新到文件中
4 释放资源(会先把内存缓冲区的数据刷新到文件中)
(字符流和字节流的最大区别:字符流不是直接把数据写到文件中,而是写入到内存中去。) -
flush方法和close方法的区别:
- flush:刷新缓冲区,流对象可以继续使用
- close:先刷新缓冲区,然后通知系统释放资源,流对象不可以再被使用了 -
续写和换行(构造方法传递参数)
FileWriter(String fileName, boolean append)
FileWriter(File file, boolean append)-
参数:
- String fileName,File file:写入数据的目的地
- boolean append:续写开关,true:创建对象不会覆盖源文件,继续在文件末尾追加写数据,false:创建一个新文件,覆盖源文件 -
换行:写换行符号
windows:\r\n
linux:\n
mac:\r
-
//写单个字符
public class demo07Writer {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("D:\\Eclipse\\workplace\\day1\\src\\num10\\d.txt");
fw.write(97); //a 写单个字符void write(int c)
//必须调用flush或close方法,将数据从内存刷新到文件中
fw.flush(); //把数据刷新到流中
fw.write(98); //ab
fw.close(); //释放资源(会先把内存缓冲区的数据刷新到文件中)
//close方法后,流已经关闭了,从内存中消失,流不能再使用
// fw.write(99); 异常: java.io.IOException: Stream closed
}
}
//写多个字符
public class demo08Writer {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("D:\\Eclipse\\workplace\\day1\\src\\num10\\f.txt",true); //续写
//1 void write(char[] cbuf) 写入字符数组。
char[] cs = {'a','b','c','d','e'};
fw.write(cs); //abcde
//2 void write(char[] cbuf, int off, int len) 写入字符数组的某一部分
fw.write(cs,1,3); //bcd
//3 void write(String str) 写入字符串。
fw.write("泡泡你好");
fw.write("你真的非常棒", 3, 3);
for (int i = 0; i < 10; i++) {
fw.write("hello"+i);
fw.write("\r\n"); //换行
}
fw.close();
}
}
异常的处理
-
使用try…catch处理流中的异常
格式: try{ //可能产生异常的代码 }catch(异常类变量 变量名){ //异常的处理逻辑 }finally{ //一定会执行的代码 资源释放 }
public class demo09Exception {
public static void main(String[] args) {
//提高变量fw的作用域,让finally可以使用
//变量在定义的时候,可以没有值,但在使用的时候必须有值
//fw = new FileWriter("D:\\Eclipse\\workplace\\day1\\src\\num10\\f.txt",true);如果执行失败,fw就没有值,fw.close()就会报错
FileWriter fw = null;
for (int i = 0; i < 10; i++) {
try {
fw = new FileWriter("w:\\Eclipse\\workplace\\day1\\src\\num10\\f.txt",true); //FileNotFoundException系统找不到指定的路径
fw.write("hello"+i+"\r\n");
} catch (IOException e) {
e.printStackTrace();
}finally {// 无论是否出现异常,都资源释放
//创建对象失败,fw的默认值是null,而null是不能调用方法的,会抛出NullPointerException,需要增加一个判断,不是null再把资源释放
if(fw != null) { //不加判断会出现空指针异常
try {
fw.close(); //fw.close方法声明抛出了IOException异常对象,所以我们就得处理这个异常对象,要么就try..catch
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
- 改进(了解)
-
jdk1.7新特性:
在try后面可以加一个(),在括号中可以定义流对象,那么这个流对象就在try中有效,try中的代码执行完毕,会自动把流对象释放,不用谢写inally -
格式:
try(定义流对象,流对象,流对象...){ //可能产生异常的代码 }catch(异常类变量 变量名){ //异常的处理逻辑 }
//文件复制的例子
public class demo10Exception {
public static void main(String[] args) { //不用写finally,流对象定义在try的括号中
try(// 创建一个字节输出流对象,构造方法中绑定要写入的目的地
FileOutputStream fos = new FileOutputStream("D:\\Eclipse\\workplace\\day1\\src\\num10\\c.txt");
//创建一个字节输入流对象,构造方法绑定要读取的数据源
FileInputStream fis = new FileInputStream("D:\\Eclipse\\workplace\\day1\\src\\num10\\demo01OutputStream.java");
) {
int len = 0;
while((len = fis.read())!= -1) { // fis.read每次读入一个字节,len为有效读取的字节
//使用字节输出流对象中的方法write,把读取到的字节写入目的地的文件中
fos.write(len);
}
} catch (Exception e) {
System.out.println(e);
}
}
}
- jdk9新特性:
- 在try前边可以定义流对象,在try后面的()中可以直接引入流对象的名称(变量名)
- 在try中的代码执行完毕,会自动把流对象释放,不用写finally- 格式:
A a = new A();
B b = new B();
try(a,b){
//可能产生异常的代码
}catch(异常类变量 变量名){
//异常的处理逻辑
}
- 格式:
//jdk1.9 建议使用jdk1.7
public class demo11Exception {
public static void main(String[] args) throws IOException { //不用写finally,流对象定义在try的括号中
// 创建一个字节输出流对象,构造方法中绑定要写入的目的地
FileOutputStream fos = new FileOutputStream("D:\\Eclipse\\workplace\\day1\\src\\num10\\c.txt");
//创建一个字节输入流对象,构造方法绑定要读取的数据源
FileInputStream fis = new FileInputStream("D:\\Eclipse\\workplace\\day1\\src\\num10\\demo01OutputStream.java");
try(fis;fos) {
int len = 0;
while((len = fis.read())!=-1) { // fis.read每次读入一个字节,len为有效读取的字节
//使用字节输出流对象中的方法write,把读取到的字节写入目的地的文件中
fos.write(len);
}
} catch (Exception e) {
System.out.println(e);
}
fos.write(1); //Stream Closed 已经关闭流了
}
}