面向字符的流有Reader类(输入字符基类)和Writer类(输出字符基类),他们不同的子类分为节点流(读取或写入数据)和处理流(对数据进行某种处理)
节点流
CharArrayReader
FileReader
PipedReader
StrinReader
CharArrayWriter
PipedWriter
StringWriter
处理流
BufferReader—LineNumberReader
InputStreamReader--<FileReader>
FilerReader—PushbackReader
BufferWriter
OutputStreamReader—<FileWriter>
FileWriter用于读取字符流
FilerWriter 用于读取已过滤的字符流的抽象类
InputStreamReader是字节转字符,输入流中的字节转字符,InputStreamReader 中的一个read() 方法都会导致从底层输入流读取一个或多个字节,可以使用BufferedReader提前从底层流读取更多的字节,以达到最高效率
[注:System.in是字节流]
FilterReader 的子类应重写这些方法中的一些方法,并且还可以提供一些额外的方法和字段。
In和out的对象都是内存,进入到内存、从内存出
Input是从文件、缓冲区或输入中读取(字符或字节)到内存
Output是从内存写入到文件、缓冲区或输出
Inputstream是基类
Inputstream类的read()方法从输入流中读取数据的下一个字节。
FileInputStream 从文件系统中的某个文件中获得输入字节或用于读取诸如图像数据之类的原始字节流
FileOutputStream 用于将数据写入 File 或 FileDescriptor 的输出流或写入诸如图像数据之类的原始字节的流
[字节流和字符流的读取方式]
字节流可以逐字节读取,用read()方法,字符流可以逐行读取,用readline()方法
[注]文本文件写入
1、创建指定文件输入流对象FileWriter对象
2、调用输入流对象的write(“...”)向流中写入数据
3、关闭流
[注]文本文件读取
1、创建文件输入流FileReader并放入缓冲流对象BufferReader之中
2、调用缓冲流对象BufferReader的readline()方法读取流中的一行内容
3、用循环读完流中所有数据
4、关闭流
[什么时候用到缓冲流BufferReader]
输入的字符流首先要用InputStreamReader类转字符流为字节流,同时最好放入缓冲流BufferReader对象中,提高效率。
总结说就是**Reader类对象读取字符,交给**InputStream对象转换为字节流,或者InputStream对象读取系统标准输入流(System.in)再交给缓冲流对象BufferReader,就可以调用缓冲流的相应方法进行处理(in.readline());
若此时需要接着对输入的数据进行输出类型处理,就可以先创建与之相配合的OutputStream子类对象,再调用OutputStream子类对象的相应方法进行处理。
BufferedReader从字符输入流中读取文本,缓冲各个字符, Reader类 所作的每个读取请求都会导致对底层字符或字节流进行相应的读取请求,建议用 BufferedReader 包装所有其 read() 操作可能开销很高的 Reader(如 FileReader 和 InputStreamReader
BufferedInputStream 为另一个输入流添加一些功能
[注]使用各种缓冲Buffer*是为了提高效率
缓冲解决输入输出速度不匹配问题
建议用 BufferedReader 包装所有其 read() 操作可能开销很高的 Reader(如 FileReader 和 InputStreamReader)。例如,
BufferedReader in
= new BufferedReader(new FileReader("System.in"));
通常 Writer 将其输出立即发送到底层字符或字节流。除非要求提示输出,否则建议用 BufferedWriter 包装所有其 write() 操作可能开销很高的 Writer(如 FileWriters 和 OutputStreamWriters)。例如,
PrintWriter out
= new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
将缓冲 PrintWriter 对文件的输出。如果没有缓冲,则每次调用 print() 方法会导致将字符转换为字节,然后立即写入到文件,而这是极其低效的。
[问题]读取文本文件时如果文件不存在会发java.io.FileNotFoundException异常,而不是FileNotFoundException异常?写入字符到文本文件时,若目标文件不存在,则会直接创建该文件。
[关于文本文件写入文本内容]
1、System.in是字节标准输入流,两种方式转为字符流,一是用InputStreamReader 类进行字节转字符,InputStreamReader in=new InputStreamReader(System.in),用in.readline()方法接收一行内容。二是用Scanner类,Scanner scan=new Scanner(System.in);用scan.next()方法接收输入内容空格之前的内容(空格之后的内容会忽略),可以加参数拆分,得到的是字符流(即String)。
2、文本文件写入分为字节流写入和字符流写入,进而又分为直接写入和经缓冲区写入
字节流写入:
InputStream ir = System.in;// 创建字节输入流并接收标准输入流
BufferedInputStream in = new BufferedInputStream(ir);// 放入字节缓冲流
byte buff[] = new byte[299];
int len = 0;
FileOutputStream out = new FileOutputStream(fileName, true); // 创建指定名字的输出字节流对象,指定为追加模式
len = in.read(buff);//
// 从此输入流中读取下一个数据字节。返回一个 0 到 buff长度 范围内的 int
// 字节值。如果因为已经到达流末尾而没有字节可用,则返回 -1。
System.out.println(len);
out.write(buff, 0, len);//
// 字节流会自动加入回车键按下的换行,同时每次循环都调用字节缓冲流in,而in一直接收标准输入流
// System.in,所以程序会一直等待输入
/*
* while((len=in.read(buff))>0){ out.write(buff,0,len); }
*/
out.close();
字符流写入(使用输出缓冲):
// 创建一个扫描器对象接收输入
Scanner scan = new Scanner(System.in);
String sc ;//
FileWriter writer = new FileWriter(fileName, true); // //创建指定名字的字符输出流对象,指定为追加模式
BufferedWriter out = new BufferedWriter(writer);// writer.write("\n");//文件中写入换行符
sc=scan.nextLine();
out.newLine();
out.write(sc);
/*while (scan.hasNextLine()) {
sc = scan.nextLine();
out.newLine();// 写入换行
out.write(sc);
out.flush();
}*/
out.close();
writer.close();
scan.close();
[注]有几个小细节
1、将Filewriter对象关闭的语句写入while循环内,才会成功写入文件。或者把Filewriter对象的flush()方法写入while循环体内。但是Junit测试都通不过(这里没通过的原因是程序还在循环体中没有结束。)Filewriter对象关闭的语句会同时flush()。
[Junit测试如果方法内调用了该类的字段或属性,则junit测试会报错]
2、在控制台字节输入流接收System.in时,回车键按下不仅发送确定指令而且代表的换行会自动写入文本文件,若是复制的文本中有换行,也会自动发送确定指令。
3、字符流要想输入换行,使用“\n”是不行的,控制台可以识别但txt文件会忽略,想要实现换行必须使用字符输出缓冲BufferedWriter对象的newLine()方法,由此可知缓冲提供的的功能更全面。
4、scanner对象next()方法默认接收第一个空格之前的字符,nextLine()方法默认接收一行内容