转载自:http://blog.csdn.net/qq_25525909/article/details/47210825
很通俗实用。
IO流
字符流的抽象基类:Reader Writer
字节流的抽象基类:OutputStream InputStream
由这四个派生出来的子类名称都是以其父类名作为子类名的后缀,方便于查看。
通过查阅api文档,梳理IO流中重要的接口与类关系分支:
字符流:
Reader:用于读取字符流的抽象类。子类必须实现的方法(是抽象方法): read(char[], int, int) 和 close()。
|---BufferedReader:从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。 可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
|---LineNumberReader:跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。
|---InputStreamReader:是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
|---FileReader:用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader。
Writer:用于写入字符流的抽象类。子类必须实现的方法(是抽象方法): write(char[], int, int)、flush() 和 close()。
|---BufferedWriter:将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
|---OutputStreamWriter:是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
|---FileWriter:用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。要自己指定这些值,可以先在 FileOutputStream 上构造一个 OutputStreamWriter。
|---PrintWriter: 向文本输出流打印对象的格式化表示形式。
InputStream:是表示字节输入流的所有类的超类。
|--- FileInputStream:从文件系统中的某个文件中获得输入字节。哪些文件可用取决于主机环境。FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader。
|--- FilterInputStream:包含其他一些输入流,它将这些流用作其基本数据源,它可以直接传输数据或提供一些额外的功能。
|--- BufferedInputStream:该类实现缓冲的输入流。
|--- PipedInputStream: 管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节
字节流:
OutputStream:此抽象类是表示输出字节流的所有类的超类。
|--- FileOutputStream:文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流。
|--- FilterOutputStream:此类是过滤输出流的所有类的超类。
|--- BufferedOutputStream:该类实现缓冲的输出流。
|--- PrintStream: PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。为了自动刷新,可以创建一个PrintStream;这意味着可在写入 byte 数组之后自动调用 flush 方法,可调用其中一个println 方法,或写入一个换行符或字节 ('\n')。
|--- DataOutputStream: 数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。然后,应用程序可以使用数据输入流将数据读入。
|--- PipedOutputStream:可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。
1.FileWriter&FileReader
IO流是操作数据的,数据最常见的体现形式是文件,那么专门用于操作文件的Writer子类
FileWriter和Reader子类FileReader是用于操作(写入和读取)字符文件的便捷类。
这里以拷贝一个文本文件为范例来阐述这两类的用法:
需求:将c盘a.txt文本文件拷贝到d盘b.txt文本文件下
分析:需要创建一个文件读取流和文件写入流对象,和指定名称的文件相关联(必须保证文件已存在,若不存在,会发生FileNotFoundException异常,从两者都没有空参的构造函数也可看出).调用各自的方法完成文件的读取和写入,最后需要流资源。
代码示例如下:
- package com.gzj.io;
- /*
- 步骤:
- 1,在D盘创建一个文件。用于存储C盘文件中的数据。
- 2,定义读取流和C盘文件关联。
- 3,通过不断的读写完成数据存储。
- 4,关闭资源。
- */
- import java.io.*;
- class CopyText
- {
- public static void main(String[] args) throws IOException
- {
- FileWriter fw = null;//在外面建立引用,在内进行初始化,这样变量才能作用于整个类
- FileReader fr = null;
- try
- {
- fw = new FileWriter("demo");//该步就是在明确数据要存放的目的地
- fr = new FileReader("demo2");
- char[] buf = new char[1024];
- int len = 0;
- while((len=fr.read(buf))!=-1)//调用读取流对象的read(char[] cbuf)方法,返回读取的字符数
- {
- fw.write(buf,0,len);//调用写入流对象的write(char[] cbuf,int off,int len)方法
- }
- }
- catch (IOException e)
- {
- throw new RuntimeException("读写失败");
- }
- finally
- {
- if(fr!=null)
- try
- {
- fr.close();
- }
- catch (IOException e)
- {
- }
- if(fw!=null)
- try
- {
- fw.close();
- }
- catch (IOException e)
- {
- }
- }
- }
- }
2.BufferedWriter&BufferedReader(字符流写入缓冲区和字符流读取缓冲区)
缓冲区的出现是为了提高流的操作效率,所以在创建缓冲区之前,都必须要先有流对象。另外,需要强调的是BufferedWriter中提供了一个跨平台的换行符newLine(),以及BufferedReader提供了一个一次读取一行数据的方法readLine(),方便对文本的读取。返回值类型是字符串,当返回null时,表示读到文件末尾。要注意的是,该方法只返回回车符之前的数据内容,所以读取数据的同时写入数据后,需要换行newLine()。这里再次以拷贝文本文件的代码示例来体现这两类的实际应用:
需求:通过缓冲区复制文本文件
- /*
- 通过缓冲区复制一个文本文件。
- */
- import java.io.*;
- class CopyTextByBuf
- {
- public static void main(String[] args)
- {
- BufferedReader bufr = null;
- BufferedWriter bufw = null;
- try
- {
- bufr = new BufferedReader(new FileReader("demo"));//传入一个读取流对象
- bufw = new BufferedWriter(new FileWriter("demo2"));//传入一个写入流对象
- String line = null;//相当于一个中转站
- while((line=bufr.readLine())!=null)//一行行读取
- {
- bufw.write(line);
- bufw.newLine();//换行
- bufw.flush();//写入一行刷新一行
- }
- }
- catch (IOException e)
- {
- throw new RuntimeException("读写失败");
- }
- finally
- {
- try
- {
- if(bufr!=null)
- bufr.close();
- }
- catch (IOException e)
- {
- throw new RuntimeException("读取关闭失败");
- }
- try
- {
- if(bufw!=null)
- bufw.close();
- }
- catch (IOException e)
- {
- throw new RuntimeException("写入关闭失败");
- }
- }
- }
- }
3.LineNumberReader
它是BufferedReader的子类,也是属于装饰类。是添加了跟踪行号功能的缓冲字符输入流。此类定义了方法 setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。
代码示例如下:
- import java.io.*;
- class LineNumberReaderDemo
- {
- public static void main(String[] args)throws IOException
- {
- FileReader fr = new FileReader("PersonDemo.java");
- LineNumberReader lnr = new LineNumberReader(fr);//将字符读取流对象作为参数传
- //给缓冲对象的构造函数
- String line = null;
- lnr.setLineNumber(100);
- while((line=lnr.readLine())!=null)
- {
- System.out.println(lnr.getLineNumber()+":"+line);//读一行数据打印一行数据
- }
- lnr.close();//关闭缓冲流
- }
- }
4.FileInputStream&FileOutputStream
FileInputStream和FileOutputStream是用于读取诸如图像数据之类的原始字节流。当我们需要操作如图片,声音等文件时就需要用到这两类流来操作。这里以复制一个图片为例截取部分代码:
public static void main(String[] args)
{
FileOutputStreamfos = null;
FileInputStreamfis = null;
try
{
fos= new FileOutputStream("c:\\2.bmp");
fis= new FileInputStream("c:\\1.bmp");
byte[]buf = new byte[1024];//new一个缓冲区
intlen = 0;
while((len=fis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
}
5.BufferedInputStream&BufferedOutputStream(字节流写入缓冲区与字符流写入缓冲区)
顾名思义,是操作字节流的缓冲区。那么BufferedInputStream里面定义了读取等方法
BufferedOutputStream里面定义了写入等方法。
这里以复制mp3文件为例截取部分代码:
publicstatic void copy_1()throws IOException
{
BufferedInputStream bufis =new BufferedInputStream(new FileInputStream("c:\\0.mp3"));
BufferedOutputStream bufos =new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));
int by = 0;
while((by=bufis.read())!=-1)
{
bufos.write(by);
}
bufos.close();
bufis.close();
}
6. InputStreamReader& OutputStreamWriter(读取转换流与写入转换流)
转换流特有功能:转换流可以将字节转成字符,(将获取到的字节通过查编码表获取到指定对应字符。)
基于 字节流 + 编码表 。没有转换,没有字符流。
发现转换流有一个子类就是操作文件的字符流对象:
InputStreamReader
|--FileReader
OutputStreamWriter
|--FileWrier
想要操作文本文件,必须要进行编码转换,而编码转换动作转换流都完成了。所以操作文件的流对象只要继承自转换流就可以读取一个字符了。
但是子类有一个局限性,就是子类中使用的编码是固定的,是本机默认的编码表,对于简体中文版的系统默认码表是GBK。
FileReader fr = new FileReader("a.txt"); 等价于
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"gbk");
如果仅仅使用平台默认码表,使用FileReader fr = new FileReader("a.txt"); 即可。 如果需要指定编码表,必须用转换流。
转换流 = 字节流+编码表。
转换流的子类File = 字节流 + 默认编码表。
凡是操作设备上的文本数据,涉及编码转换,必须使用转换流。
代码示例:
- import java.io.*;
- class TransStreamDemo
- {
- public static void main(String[] args) throws IOException
- {
- //获取键盘录入对象。
- //InputStream in = System.in;
- //将字节流对象转成字符流对象,使用转换流。InputStreamReader
- //InputStreamReader isr = new InputStreamReader(in);
- //为了提高效率,将字符流进行缓冲区技术高效操作。使用BufferedReader
- //BufferedReader bufr = new BufferedReader(isr);
- //键盘的最常见写法。
- BufferedReader bufr =
- new BufferedReader(new InputStreamReader(System.in));
- //OutputStream out = System.out;
- //OutputStreamWriter osw = new OutputStreamWriter(out);
- //BufferedWriter bufw = new BufferedWriter(osw);
- //键盘输出
- BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
- String line = null;
- while((line=bufr.readLine())!=null)
- {
- if("over".equals(line))//自定义键盘结束标记
- break;
- bufw.write(line.toUpperCase());
- bufw.newLine();
- bufw.flush();
- }
- bufr.close();
- }
- }
7.PrintStream&PrintWriter(字节打印流与字符打印流)
打印流:该流提供了打印方法,可以将各种数据类型的数据都原样打印。
字节打印流:
PrintStream
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
字符打印流:
PrintWriter
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
4,字符输出流,Writer。
- import java.io.*;
- class PrintStreamDemo
- {
- public static void main(String[] args) throws IOException
- {
- BufferedReader bufr =
- new BufferedReader(new InputStreamReader(System.in));//源:读取键盘输入
- //目的:控制台,控制台对应的对象是字节输出流
- PrintWriter out = new PrintWriter(System.out,true);
- String line = null;
- while((line=bufr.readLine())!=null)
- {
- if("over".equals(line))
- break;
- out.println(line.toUpperCase());//打印方法,附带换行操作,并可以刷新
- //out.flush();
- }
- out.close();//关闭打印流
- bufr.close();//关闭键盘录入
- }
- }