输入与输出流
在Java中,信息的输入和输出(I/O)是程序设计语言中的一个很重要的部分。在任何程序中都离不开信息的输入和输出。在面向对象语言中,输入和输出都是通过数据流来实现的。处理数据流的类主要被放在包java.io中。因为前面已经讲过I/O流的基本知识,所以下面只是对之前只是的巩固和补充。
1、数据流的划分
按照处理数据的单位划分,Java定义了两种类型的数据流:字节流和字符流。字节流是用来处理字节的输入和输出的,各种数据都可以用字节来表示,包括数字数据、程序和字节码等。字符流是用来处理字符的输入和输出的,它只处理文本化的数据,任何涉及文本的数据类型都应该使用字符流,包括文本文件、网页以及其他的文本类型。
字节流类InputStream和OutputStream是两个抽象类,InputStream包括了字节输入流的所有方法,OutputStream包括了字符输出流的所有方法。真正用来做数据输入和输出处理的是这两个抽象类的各个具体的子类。这些子类可以针对不同的输入和输出进行处理。下面是输入字节流与输出字节流的表:
流 |
描 述 |
FileInputStream |
文件字节输入流 |
ByteArrayInputStream |
字节数组输入流 |
PipedInputStream |
管道输入流 |
BufferedInputStream |
缓冲输入流 |
FilterInputStream |
过滤字节输入流 |
ObjectInputStream |
对象输入流 |
DataInputStream |
包含读取Java标准数据类型方法的输入流 |
流 |
描 述 |
FileOutputStream |
文件字节输出流 |
ByteArrayOutputStream |
字节数组输出流 |
PipedOutputStream |
管道输出流 |
BufferedOutputStream |
缓冲输出流 |
FilterOutputStream |
过滤字节输出流 |
ObjectOutputStream |
对象输出流 |
DataOutputStream |
包含读取Java标准数据类型方法的输出流 |
PrintStream |
包含print()和println()的输出流 |
通过这些字节输入流和字节输出流类来创建数据流一遍完成数据的输入和输出。例如将影像、声音等数据写入文件和从文件里读取数据时,就要用到FileInputStream和FileOutputStream类。
字符流类Reader和Writer也是两个抽象类。由于Java采用16位的Unicode字符编码,所以这些抽象类处理的是Unicode的字符流。用来作数据输入和输出处理的是Reader和Writer的子类,这些子类可以针对不同的输入和输出进行处理。输入和输出字符流如下表所示:
输入字符流
流 |
描 述 |
FileReader |
文件字符输入流 |
CharArrayReader |
从字符数组读取的输入流 |
StringReader |
读取字符串的输入流 |
PipedReader |
管道字符输入流 |
BufferedReader |
缓冲输入流 |
FilterReader |
过滤字符输入流 |
InputStreamReader |
将字节输入流转换为字符输入流 |
输出字符流
流 |
描 述 |
FileWriter |
文件字符输出流 |
CharArrayWriter |
从字符数组读取的输出流 |
StringWriter |
读取字符串的输出流 |
PipedWriter |
管道字符输出流 |
BufferedWriter |
缓冲输出流 |
FilterWriter |
过滤字符输出流 |
OutputStreamWriter |
将字节输出流转换为字符输出流 |
PrintWriter |
打印字符输出流 |
上表中这些字符输入流和字符输出流都是抽象类Reader和Writer的子类,可以通过这些字符输入流和字符输出流来创建数据流以便完成数据的输入和输出。例如将”纯文本”数据写入文件和从文件里读取数据时,就要用到FileReader和FileWriter类。
2、字节流
字节流是以字节为单位进行读写数据的。InputStream和OutputStream类分别是字节输入流类和字节输出流类的抽象超类,包括了字节输入和输出的所有方法。
1)、通过字节流读写数据
Java中所有有关输入和输出的类都是从InputStream类和OutputStream类继承的。因为InputStream类和OutputStream类都是抽象的,仅提供了基本的函数类型,没有具体实现,所以不能直接生成对象。要通过其子类来生成所需的对象,同时必须重写InputStream类和OutputStream类中的方法。InputStream类时字节输入流类的超类,描述了所有字节输入的方法。下面是InputStream的主要方法。
>int read():从输入流中读取下一个字节,并以int类型返回。返回值的取值范围为0~255,若遇到输入流的末尾则返回-1。下面是对read()方法的重写:
>int read(byte b[]):从输入流中读取长度为b.length的字节到b中,并返回本次读取的字节流。如果遇到输入流的末尾则返回-1.
>int read(byte b[] , int off , intlen):与上面不同的是读取长度为len的字节,写入b从下标off开始的位置。
>void close():关闭当前的输入流,同时释放相关的系统资源。
>int available():返回当前输入流中可读取的字节数。
OutputStream是字节输出流类的超类,描述了所有字节输出的方法。下面是OutputStream的主要方法:
>void write(int b):将制定的字节b作为数据写入输出流。该方法的属性的abstract,因此必须在子类中实现。下面是对其的重写:
>voidwrite(byte b[]):将字节数组b中长度为b.length个字节的数据写入;
>void wirte(byte b[] , int off , intlen):将b中下标off开始的长度为len个字节的数据写入输出流。
>flush():刷新输出流;
>close():关闭当前的输出流,同时释放相关的系统资源。
2)、FileInputStream类
FileInputStream类继承了InputStream类,它重写的父类中的所有方法。FileInputStream类用于进行文件的输入处理,其数据源和接受器都是文件。FileInputStream类的两个常用的构造函数为:
FileInputStream(StringfilePath)和FileInputStream(File fileObj)
下面的实例详细讲解了read方法:
public classmytest01 { public static void main(String[] args) { try { //创建一个FileInputStream对象 FileInputStream file = newFileInputStream("D:\\桌面\\安卓开发工具\\学习笔记\\test.txt"); while (file.available() > 0){ //调用read方法 System.err.println((char)file.read()); } file.close(); } catch (Exception e) { System.err.println(e.getMessage()); } } }
3)、FileoutputStream类
FileOutputStream类的构造函数和FileInputStream类的构造函数不同,它的构造函数有3中形式,其构造函数的形式如下:
FileoutputStream(StringfilePath)
FileoutputStream(FilefileObj)
FileoutputStream(StringfilePath , Boolean append)
其中filePath是指被打开并且需要写入数据的文件名。fileObj是指被打开并且需要写入数据的文件。参数append为true时,文件以追加方式打开,不覆盖已有文件的内容;为false则覆盖源文件的内容。
FileOutputStream对象的创建不依赖文件是否存在。如果文件不存在,FileOutputStream会在打开输出文件之前创建它。如果文件已经存在,则打开它并写入内容。如果文件是只读的,会引发一个IOException异常。下面是文件的复制操作:
public class test{ public static void main(String[] args) { int i; try { FileInputStream aa = newFileInputStream("D:\\桌面\\桌面\\安卓开发工具\\学习笔记\\test1.txt"); FileOutputStream bb = newFileOutputStream("D:\\桌面\\桌面\\安卓开发工具\\学习笔记\\test2.txt"); bb.write('0'); bb.write('7'); bb.write('.'); bb.write('8'); bb.write('.'); bb.write('1'); //从此输入流中读取一个数据字节 i = aa.read(); while (i != -1) { bb.write(i); i = aa.read(); } aa.close(); bb.close(); System.out.println("运行完毕"); } catch (Exception e) { System.err.println(e.getMessage()); } } }
4)、用快捷方式读取特定信息
我们已经知道了数据流处理的数据都是指字节或字节数组,但实际上很多时候不是这样的,它需要数据流能只能读/写各种各样的Java语言的基本数据类型。例如要读取文件中存放的300个整数值,从中读取时,希望以int为基本单位进行读取,这样可以大大节省时间。这时就需要使用DataInputStream和DataOutputStream,它们不但支持父类InputStream和OutputStream中的方法,以原有方式读写数据,同时还允许通过数据流来读写Java语言的基本数据类型,包括int、float、double和boolean等,其构造函数如下:
DataInputStream(已经建立好的输入数据流对象)
DataOutputStream(已经建立好的输出数据流对象)
它们之所以能够对这些原始类型进行操作,是因为它们有一组特定的方法。具体方法可以参考API,下面是主要方法:
DataInputStrean:
readByte() ,readLong() , readDouble() , readBoolean() , String readUTF() , readInt() ,readFloat() , readShort() , readChar().
DataOutputStream:
writeByte() ,writeLong() , writeDouble() , writeBoolean() , WriteUTF() , writeInt() ,writeChar() , writeFloat() , writeShort().
下面是一段关于这两个类的使用:
public staticvoid main(String[] args) { int i; try { FileOutputStream bb = newFileOutputStream("D:\\桌面\\桌面\\安卓开发工具\\学习笔记\\test2.txt"); DataOutputStream da = newDataOutputStream(bb); da.writeInt(12); da.writeInt(13); da.writeDouble(12.34534); da.writeBoolean(true); da.writeChars("这是Java数据流#"); bb.close(); FileInputStream aa = newFileInputStream("D:\\桌面\\桌面\\安卓开发工具\\学习笔记\\test2.txt"); DataInputStream di = newDataInputStream(aa); System.err.println(di.readInt()); System.err.println(di.readDouble()); System.err.println(di.readBoolean()); char cc = '0'; while (true) { cc = di.readChar(); if (cc == '#') break; System.err.print(cc); } System.err.println("\n"); aa.close(); System.out.println("运行完毕"); } catch (Exception e) { System.err.println(e.getMessage()); } }
5)、引入缓冲刘读取文件
文件字节输入/输出流是以字节为单位进行读/写操作的,这使得文件流的效率很低,这是就需要用到BufferedInputStream和BufferdOutputStream类。当输入数据时,数据以块为单位读入缓冲区,伺候如有读操作,则直接访问缓冲区。当输出数据时,数据不直接向输出流输出数据,而是将数据先写入缓冲区,当缓冲区的数据满时,才将缓冲区中的数据写入输出流中。这样就提高了I/O操作的效率。
它们都是InputStream/OutputStream的子类,其构造方式如下:
BufferedInputStream(已创建好的输入数据流对象)
BufferedOutputStream(已创建好的输出数据流对象)
下面是一段演示缓冲流的代码:
public staticvoid main(String[] args) { FileInputStream fis; FileOutputStream fos; BufferedInputStream bis; BufferedOutputStream bos; int i; try { fis = newFileInputStream("D:\\桌面\\桌面\\安卓开发工具\\学习笔记\\test1.txt"); fos = newFileOutputStream("D:\\桌面\\桌面\\安卓开发工具\\学习笔记\\test2.txt"); bis = new BufferedInputStream(fis); bos = newBufferedOutputStream(fos); //从输入数据流中读取一个字节 i = bis.read(); while (i != -1) { bos.write(i); bos.flush(); i = bis.read(); } fis.close(); fos.close(); bis.close(); bos.close(); System.err.println("运行结束"); } catch (Exception e) { e.printStackTrace(); } }