---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------
1. 什么是IO流:
流是一个抽象的概念。当Java程序需要从数据源读取数据时,会开启一个到数据源的流。数据源可以是文件,内存或者网络等。同样,当程序需要输出数据到目的地时也一样会开启一个流,数据目的地也可以是文件、内存或者网络等。流的创建是为了更方便地处理数据的输入输出。
IO流根据处理数据类型的不同分为:字符流和字节流;根据数据流向不同分为:输入流和输出流
Java 的流式输入/输出建立在四个抽象类的基础上:InputStream, OutputStream,Reader和Writer。它们用来创建具体流式子类。尽管程序通过具体子类执行输入/输出操作,但顶层的类定义了所有流类的基本通用功能。
InputStream 和OutputStream 设计成字节流类。Reader 和Writer 为字符流设计。字节流类和字符流类形成分离的层次结构。一般说来,处理字符或字符串时应使用字符流类,处理字节或二进制对象时应用字节流类。
操作文件流时,不管是字节流还是字符流都可以按照以下的方式进行:
a) 使用File类找到一个文件;
b) 通过File类的对象去实例化字节流或字符流的子类;
c) 进行字节(字符)的读、写操作;
d) 关闭文件流;
2. Java中的字节流:
字节流类以InputStream 和OutputStream为顶层。下面分别介绍这两种字节流:
a) 字节输入流InputStream:
InputStream 是所有的输入字节流的父类,它是一个抽象类。它的子类中ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。PipedInputStream 是从与其它线程共用的管道中读取数据。ObjectInputStream 和所有FilterInputStream 的子类都是装饰流。
它们的继承关系简要表示如下:
InputStream:是表示字节输入流的所有类的超类。
|--- FileInputStream:从介质中获得输入字节。可用于读取诸如图像数据之类的原始字节流。
|--- FilterInputStream:装饰流,包含其他一些输入流,它将这些流用作其基本数据源,它可以直接传输数据或提供一些额外的功能。
|--- BufferedInputStream:该类实现缓冲的输入流。
|--- ObjectInputStream:装饰流
|--- PipedInputStream:从与其它线程共用的管道中读取数据。
b) 字节输出流OutputStream:
OutputStream 是所有的输出字节流的父类,它是一个抽象类。它的子类中ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据,ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰流。
它们的继承关系简要表示如下:
OutputStream:此抽象类是表示输出字节流的所有类的超类。
|--- FileOutputStream:是用于将数据写入介质的输出流。
|--- FilterOutputStream:此类是过滤输出流的所有类的超类。
|--- BufferedOutputStream:该类实现缓冲的输出流。
|--- PrintStream:
|--- DataOutputStream:
|--- ObjectOutputStream:
|--- PipedOutputStream:向与其它线程共用的管道中写入数据。
3. 字节流中的FileInputStream 与 FileOutputStream:
FileInputStream 类创建一个能从文件读取字节的InputStream 类,它的两个常用的构造方法如下:
FileInputStream(String filePath):其中的filePath为文件的路径;
FileInputStream(File file)
FileInputStream 类中的read方法中有两个最常用:
read():可以一次读取一个字节;
read(byte[] b):可一次读取多个字节存入字节数组中。
FileOutputStream 创建了一个可以向文件写入字节的类OutputStream,它常用的构造方法如下:
FileOutputStream(String filePath):其中的filePath为文件的路径;
FileOutputStream(File file)
FileOutputStream(String filePath, booleanappend):append若为true,代表在原文件末尾追写数据,而不进行数据覆盖;
FileOutputStream中的write()方法,有两个最常用:
write(int b):可将指定字节写入文件输出流,注意,b的类型虽然是int(四个字节),但是write方法会截取最后八位,所以最终写入文件输出流的只是一个字节。
write(byte[] b, int off, int len):将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
下面用FileInputStream 与 FileOutputStream流对一个jpg文件进行复制,代码示例如下:
importjava.io.*;
publicclass FileOutputStreamDemo {
public static void main(String[] args){
FileInputStream fis=null; //创建输入流;
FileOutputStream fos=null; //创建输出流;
try {
fis = newFileInputStream("C:/Users/FC-JAVA/Desktop/tmp/1.jpg");
fos = newFileOutputStream("C:/Users/FC-JAVA/Desktop/tmp/copy.jpg");
byte[] bts = newbyte[1024]; //创建字节数组用于存储读取到的字节;
int len = 0;
while((len = fis.read(bts)) != -1) {
fos.write(bts, 0,len);
}
} catch (Exception e) {
// TODO: handle exception
}finally{
try {
fis.close(); //关闭输入流;
} catch (IOException e) {
// TODOAuto-generated catch block
e.printStackTrace();
}
try {
fos.close(); //关闭输出流;
} catch (IOException e) {
// TODOAuto-generated catch block
e.printStackTrace();
}
}
}
}
4. Java中的字符流:
字符流类以Reader和Writer为顶层。下面分别介绍这两种字节流:
Reader:用于读取字符流的抽象类,其子类如下:
|---BufferedReader:从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。 可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
|---LineNumberReader:跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。
|---InputStreamReader:是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
|---FileReader:用来读取字符文件的便捷类。
|---CharArrayReader:
|---StringReader:
Writer:写入字符流的抽象类。其子类如下:
|---BufferedWriter:将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
|---OutputStreamWriter:是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
|---FileWriter:用来写入字符文件的便捷类。
|---PrintWriter:
|---CharArrayWriter:
|---StringWriter:
5. 字符流中的FileReader 与 FileWriter:
FileReader类创建了一个可以读取文件内容的Reader类。它最常用的构造方法如下:
FileReader(String filePath)
FileReader(File file)
每一个都能引发一个FileNotFoundException异常。这里,filePath是一个文件的完整路径,file是描述该文件的File 对象。
FileWriter 创建一个可以写文件的Writer 类。它最常用的构造方法如下:
FileWriter(String filePath)
FileWriter(String filePath, boolean append)
FileWriter(File fileObj)
它们可以引发IOException或SecurityException异常。这里,filePath是文件的绝对路径,fileObj是描述该文件的File对象。如果append为true,输出是附加到文件尾的。FileWriter类的创建不依赖于文件存在与否。在创建文件之前,FileWriter将在创建对象时打开它来作为输出。如果试图打开一个只读文件,将引发一个IOException异常。
使用FileWriter时需要注意一下几点:
a) fw.write(“aba”):将字符串写入流中,并未写入txt文件;
b) fw.flush():将流中的数据写入文件中;
c) fw.close():在关闭文件前会把数据写入文件;
d) 若要使fw.write(“abc”)把“abc”写入文件,必须有flush或close;
下面用FileInputReader 与 FileWriter对一个txt文件进行复制,代码示例如下:
importjava.io.*;
publicclass FileCopyDemo {
public static void main(String[] args){
FileWriter fw=null; //创建输入流;
FileReader fr=null; //创建输出流;
try {
fw=newFileWriter("C:/Users/FC-JAVA/Desktop/tmp/copy.txt");
fr=newFileReader("C:/Users/FC-JAVA/Desktop/tmp/1.txt");
char[] chs=newchar[1024]; //创建字符数组用于存储读取到的字符;
int len=0;
while ((len=fr.read(chs))!=-1){
fw.write(chs,0,len);
}
} catch (IOException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}finally{
if (fw!=null){
try {
fw.close(); //关闭输出流;
} catch (IOExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
if (fr!=null){
try {
fr.close(); //关闭输入流;
} catch (IOExceptione) {
// TODOAuto-generated catch block
e.printStackTrace();
}
}
}
}
}
6. 字节流与字符流效率的提高:
为了提高字节流与字符流的效率,于是有了缓冲区的加入。因为如果没有缓冲区,应用程序每次IO都要和设备进行通信,效率很低,因此为了提高效率,当写入设备时,先写入缓冲区,等到缓冲区有足够多的数据时,就整体写入设备,这样在读写大量数据时,效率就会得到明显的提高。
BufferedReader和BufferedWriter是给字符输入输出流提高效率用的,BufferedInputStream和BufferedOutputStream是给字节输入输出流提高效率用的。当要用这四个流以提高效率时,就必须先有相应的流对象。
BufferedReader提高了一次读取一行的方法readLine(),该方法方便对文本数据的读取;readLine()方法返回值类型为String,内容不包含行终止符,所以要注意需要换行的情况,通常要配合newline()方法使用;当readLine()方法返回null时,表示读到文件的末尾。
下面的代码用于演示字符缓冲流的应用,用于复制txt文件,代码如下:
importjava.io.BufferedReader;
importjava.io.BufferedWriter;
importjava.io.FileNotFoundException;
importjava.io.FileReader;
importjava.io.FileWriter;
importjava.io.IOException;
publicclass BufferedCopy {
public static void main(String[] args) {
BufferedReader bufr=null; //创建字符输入缓冲流;
BufferedWriter buwr=null; //创建字符输出缓冲流;
try {
bufr=new BufferedReader(newFileReader("C:/Users/FC-JAVA/Desktop/tmp/1.txt"));
buwr=new BufferedWriter(newFileWriter("C:/Users/FC-JAVA/Desktop/tmp/copy.txt"));
String line=null;
while((line=bufr.readLine())!=null){
buwr.write(line);
buwr.newLine();
//buwr.flush();
}
} catch (FileNotFoundException e){
// TODO Auto-generatedcatch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}finally{
if (bufr!=null){
try {
bufr.close(); //关闭字符输入流;
} catch (IOExceptione) {
// TODOAuto-generated catch block
e.printStackTrace();
}
}
if (buwr!=null){
try {
buwr.close(); //关闭字符输出流;
} catch (IOExceptione) {
// TODOAuto-generated catch block
e.printStackTrace();
}
}
}
}
}
7. 转换流:
转换流特有功能:转换流可以将字节转成字符,原因在于,将获取到的字节通过查编码表获取到指定对应字符。转换流的最强功能就是基于 字节流 + 编码表。
若要操作大量数据,还可以用的IO流的装饰类,典型写法如下:
BufferedReaderbur = new BufferedReader(new InputStreamReader(new FileInputStream(File file )));
BufferedWriterbuw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(File file )));
另附毕向东老师总结的流操作规律:
a) 明确源和目的。
数据源:就是需要读取,可以使用两个体系:InputStream、Reader;
数据汇:就是需要写入,可以使用两个体系:OutputStream、Writer;
b) 操作的数据是否是纯文本数据?
如果是:数据源:Reader
数据汇:Writer
如果不是:数据源:InputStream
数据汇:OutputStream
c) 虽然确定了一个体系,但是该体系中有太多的对象,到底用哪个呢?
明确操作的数据设备。
数据源对应的设备:硬盘(File),内存(数组),键盘(System.in)
数据汇对应的设备:硬盘(File),内存(数组),控制台(System.out)。
d) 需要在基本操作上附加其他功能吗?比如缓冲。
如果需要就进行装饰。
---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------
详细请查看:<a href="http://edu.csdn.net" target="blank">http://edu.csdn.net</a>