----------- android培训、java培训、java博客、java学习型技术博客、期待与您交流! --------------
本章主要的知识点总结:1、IO流的简单介绍和基本分类
2、操作文件字符流对象及FileWriter、FileReader的使用
3、 缓冲技术的使用和装饰设计模式以及装饰类LineNumberReader
一.IO流的简单介绍
1、IO(Input Output)流
IO流用来处理设备之间的数据传输, java对数据的操作是通过流的方式,java用于操作流的对象都在IO包中。
2、流按操作数据分为两种:字节流和字符流.
流按流向分为:输入流,输出流。
3、IO流常用基类
字节的抽象基类:InputStream OutputStream
字符流的抽象基类 Reader Writer
二、FileWriter
三、FileReader字符流的特点: IO流是用于操作数据的,那么数据的最常见体现形式是:文件。
需求: 在硬盘上,创建一个文件并写入一些文字数据。找到一个专门用于操作文件的Writer子类对象FileWriter. 后缀名是父类名。前缀名是该流对象的功能。
代码示例:
import java.io.*;
class FileWriterDemo
{
public static void main(String[] args) throws IOException
{
//该对象一被初始化就必须要明确要操作的文件,而且该文件会被创建到指定的目录下,如该目录下已有同名文件,将被覆盖。其实是明确数据的目的地
FileWriter fw = new FileWriter("a.txt);
//将字符串写到流中
fw.write("abcde");
//刷新流对象的缓冲数据,将数据刷到目的地
fw.flush();
//关闭流资源,关闭之前,会刷新一次内部的缓冲数据
fw.close();
}
}
1、IO异常的处理方式:
凡是能和设备上的数据发生关联的,调用底层的资源都会发生IOException。
比如文件路径为K\\demo.txt",而没有 K盘,会抛出FileNotFoundException(系统找不到指定的路径)异常。一般会使用try、catch、finally语句捕获处理,在finally中关闭流对象。
如果出现初始化抛出异常,说明初始化失败,fw还为空,故不可调用对象的close()方法。所以抛出NullPointerException,finally中一定要对关闭的流对象进行不等于空的判断。
2、对已有文件的书局续写
//传递true参数,表示不覆盖
FileWriter fw = new FileWriter("a.txt,true);
四、 BufferedInputStream和BufferedOutputStream
1、FileReader
public class FileReader extends InputStreamReader
用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在 FileInputStream 上构造InputStreamReader。 FileReader 用于读取字符流。要读取原始字节流,请考虑使用FileInputStream。
第一种读取方式:
代码示例:
FileReader fr = new FileReader("demo.txt");
int ch = 0;
while((ch = fr.read())!= -1)
{
System.out.println((char)ch);
}
第二种读取方式:
(1)read(char[] chs)方法
public int read(char[] cbuf)
throws IOException将字符读入数组。在某个输入可用、发生 I/O 错误或者已到达流的末尾前,此方法一直阻塞。
(2)代码演示:
FileReader fr = new FileReader("demo.txt");
char[] buf = new char[1024];
int len = 0;
while((len = fr.read(buf))!= -1){
System.out.println(new String(buf,0,num);
}
fr.close();
2、Reader类
用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。
构造方法:
protected Reader() //protected说明只有子类可使用。
创建一个新的字符流 reader,其重要部分将同步其自身的 reader。
(1)abstract void close()
关闭该流并释放与之关联的所有资源。
(2)int read()
public int read()throws IOException
读取单个字符。在字符可用、发生 I/O 错误或者已到达流的末尾前,
此方法一直阻塞。用于支持高效的单字符输入的子类应重写此方法。
返回:
作为整数读取的字符,范围在 0 到 65535 之间 (0x00-0xffff),
如果已到达流的末尾,则返回 -1
(3)int read(char[] cbuf)
将字符读入数组。 此方法返回的是读的次数。
缓冲流为IO流增加了内存缓冲区,增加内存缓冲区有两个目的:
1、允许java程序一次不只操作一个字节,这样提高了程序的性能;
2、由于有了缓冲区,使得在流上执行skip(),mark()和reset()方法都成为可能。BufferedInputStream和BufferedOutputStream是java提供的两个缓冲区包装类,不管底层系统是否使用了缓冲区,这两个类在自己的实例对象中都会创建缓冲区,底层系统提供的缓冲区直接与目标设备交换数据,而在包装类中创建的缓冲区会调用所包装类的缓冲区。
底层系统提供的缓冲区是一次性从硬盘读取大量的数据(或者写入),而包装类的缓冲区是从底层系统提供的缓冲区中一个一个的读取之后缓存起来(或者写入)。BufferedReader和BufferedWriter也是缓冲区包装类,用于包装字符流类。1、BufferedWriter
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
构造函数:
BufferedWriter(Writer out)
创建一个使用默认大小输出缓冲区的缓冲字符输出流。
newLine()
写入一个行分隔符。
代码示例:
FileWriter fw = new FileWriter("buf.txt");
//只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。
BufferedWriter bufw = new BufferedWriter(fw);
for(int x=1;x<5;x++)
{
bufw.write("abcd"+x);
bufw.newLine();
bufw.flush(); //也可以写完再刷,但是要是停电了话,缓冲区中的数据就会消失
}
//记住,只要用到缓冲区,就要记得刷新。
//bufw.flush();
//其实关闭缓冲区,就是在关闭缓冲区中的流对象。
bufw.close();
2、BufferedReader
字符读取流缓冲区:
该缓冲区提供了一个一次读一行的方法readLine,方便于对文本数据的获取。当返回null时,表示读到文件末尾。从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
通常,Reader 所作的每个读取请求都会导致对底层字符或字节流进行相应的读取请求。因此,建议用 BufferedReader 包装所有其 read() 操作可能开销很高的Reader(如 FileReader 和 InputStreamReader)。
例如, BufferedReader in = new BufferedReader(new FileReader("foo.in"));//将缓冲指定文件的输入。
如果没有缓冲,则每次调用 read() 或 readLine()都会导致从文件中读取字节,并将其转换为字符后返回,而这是极其低效的。
构造函数:
BufferedReader(Reader in)
创建一个使用默认大小输入缓冲区的缓冲字符输入流。
readLine()方法:
public String readLine() throws IOException
读取一个文本行。通过下列字符之一即可认为某行已终止:
换行 ('\n')、回车 ('\r') 或回车后直接跟着换行。
返回:包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null.
(只返回回车符之前的数据内容,并不返回回车符)。
代码示例:
////创建一个读取流对象和文件相关联。
FileReader fr = new FileReader("buf.txt");
//为了提高效率,加入缓冲技术,将字符读取流对象作为参数传递给缓冲区对象的构造函数。
BufferedReader bufr = new BufferedReader(fr);
String line = null;
while((line = bufr.readLine())!= null)
{
System.out.println(line);
}
bufr.close();
装饰设计模式:
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。那么自定义的该类称为装饰类。
装饰类通常会通过构造方法接收被装饰的对象。并基于被装饰的对象的功能,提供更强的功能。
例:自定义一个字符读取缓冲区包装类:MyBufferedReader
- class MyBufferedReader
- {
- private Reader r;
- MyBufferedReader(Reader r)
- {
- this.r = r;
- }
- public String myRead()throws IOException
- {
- int ch = 0;
- StringBuilder sb = new StringBuilder();
- while((ch = r.read())!= -1)
- {
- if(ch = '\r')
- continue;
- if(ch ='\n')
- return sb.toString();
- else
- sb.append((char)ch);
- }
- if(sb.length()!= 0)
- return sb.toString()
- return null;
- }
- public void myClose()throws IOException{
- r.close()
- }
LineNumberReader-----装饰类
public class LineNumberReader extends BufferedReader
跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。
默认情况下,行编号从 0 开始。该行号随数据读取在每个行结束符处递增,并且可以通过调用 setLineNumber(int) 更改行号。但要注意的是,setLineNumber(int) 不会实际更改流中的当前位置;它只更改将由 getLineNumber() 返回的值。
可认为行在遇到以下符号之一时结束:换行符('\n')、回车符('\r')、回车后紧跟换行符。
构造方法:
LineNumberReader(Reader in)
使用默认输入缓冲区的大小创建新的行编号 reader。
代码实例:
- class MyLineNumberReader
- {
- private Reader r;
- private int lineNumber;
- MyLineNumberReader(Reader r)
- {
- this.r = r;
- }
- public void setLineNumber(int lineNumber)
- {
- this.lineNumber = lineNumber;
- }
- public int getLineNumber()
- {
- return lineNumber;
- }
- public void myReadLine()throws IOException
- {
- lineNumber++;
- StringBuilder sb = new StringBuilder();
- int ch =0;
- while((ch = r.read())!= -1)
- {
- if(ch = '\r')
- continue;
- if(ch = '\n')
- return sb.toString();
- else
- sb.append((char)ch);
- }
- if(sb.length()!= 0)
- return sb.toString();
- return null;
- }
- }