Java IO流

  一、流的概念

  流是连续不断的数据序列的抽象描述,流提供了在不同设备之间进行I/O操作的一致性接口。

  特点:

  • 先进先出。
  • 顺序存取,无法随机访问中间数据。
  • 只读或只写。每个流只能是输入流或者输出流的一种。

  1、Java中的IO流

  按操作单位划分:

  字节流:数据操作单元是字节。

  字符流:数据操作单元是字符,一个字符占用2B。

 

  2、IO流框架和分类

  直接操作设备的流类称为结点流类,而间接流类也称为包装流类,可以装饰结点流类。

  (1)基本I/O流:

  • 字节流:InputStream,OutPutStream。
  • 字符流:Reader,Writer。

  

  (2)辅助类:

  • File
  • RandomAccessFile

  (3)New I/O流:

  • Channel
  • Buffer
  • Selector

 

  二、辅助类

  File类和 RandomAccessFile 类

  1、File类

  File类专门用于管理磁盘文件与目录,不负责数据的输入输出。可以新建、删除、重命名文件和目录、查询文件属性和处理文件目录等。

  File直接继承于Object,实现了序列化(Serializable)接口---File对象支持序列化操作,和Comparable接口---File对象之间可以比较大小。

 

  2、新建目录的3中方法

/*根据相对路径新建目录,例如,在当前路径下新建目录dir*/
File dir=new File (“dir”);
dir.mkdir ( );

/*根据绝对路径新建目录,如新建目录/home/dir*/
File dir=new File(“/home/dir”);
dir.mkdirs ( );

/*通过URI类创建目录*/
URI uri=new URI(“file:/home/edu/dir”);
File dir=new File(uri);
sub.mkdir();

  

  3、文件操作

  不同平台目录分隔符不同。为了跨平台创建代码,File中定义了分隔符。

  File中使用静态属性pathSeparator表示系统相关路径分隔符。

 

  4、文件名过滤器---FilenameFilter

  能够过滤指定类型的文件或者目录,它必须重写accept(File file,String path)方法。

 

  5、RandomAccessFile——随机文件读取

  辅助类中的RandomAccessFile类支持对文件的随机读取和写入。

  随机访问文件的行为类似存储在文件系统中的一个byte数组,存在指向该隐含数组的索引,称为文件指针。

  该类以读取/写入模式创建,则输出操作也可用。在读写时指针会自动移动。

  除了实现DataInput和DataOutput接口(两个相关的字节流类也实现了),RandomAccessFile类和字节类没有任何关系。

 

  三、字节流——InputStream&&OutPutStream

  1、InputStream

  字节输入流,是抽象类,表示字节输入流所有类的父类,所以必须依靠子类实现数据读入功能。

  有3个重载的read()方法:

  • public abstract int read():为抽象方法,需要子类具体实现。读取1B的数据,返回值是最高位补0的整型。若返回值为-1说明没有读取到任何数据,读取工作结束。其余两个是对这个抽象方法的包装。
  • public int read(byte b[]):读取长度为b.length字节的数据放回到数组b中,返回值是读取到的字节数。
  • public int read(byte b[], int off, int len):从输入流中读取len个字节的数据,存放到偏移量为off的数组b中。
  • public int available():返回输入流中可以读取的字节数。
  • public int close():在使用完后,必须将打开的流关闭。

  InputStream继承图谱

  使用建议

  Always Close Streams

  Closing a stream when it's no longer needed is very important — so important that CopyBytes uses a finally block to guarantee that both streams will be closed even if an error occurs. This practice helps avoid serious resource leaks.

  One possible error is that CopyBytes was unable to open one or both files. When that happens, the stream variable corresponding to the file never changes from its initial null value. That's why CopyBytes makes sure that each stream variable contains an object reference before invoking close.

  When Not to Use Byte Streams

  CopyBytes seems like a normal program, but it actually represents a kind of low-level I/O that you should avoid. Since xanadu.txt contains character data, the best approach is to use character streams, as discussed in the next section. There are also streams for more complicated data types. Byte streams should only be used for the most primitive I/O.

   So why talk about byte streams? Because all other stream types are built on byte streams.

 

  2、OutputStream

  字节输出流,抽象类,3个重载write()方法对应。

  • public void write(byte b[]):将参数b中的字节写到输出流;
  • public void write(byte b[],int off,int len):将参数b中从偏移量off开始的len个字节写到输出流;
  • public abstract void write(int b):先将int转换为byte类型,把低字节数据写到输出流中。

  OutputStream继承图谱:

  FilterOutputStream子类都是包装类,装饰其它结点流类。

  PrintStream是一个辅助工具类,可以向其它输出流写入数据,而且本身是带缓冲的。

  ObjectOutputStream可以将对象写入磁盘或发送到远端的进程中,但对象必须实现Serializable()接口。

 

  3、文件输入输出流---FileInputStream&&FileOutputStream

  FileInputStream:以文件作为输入源的数据流,即打开文件,从文件读取数据到内存。

  • read(),一次读取一个字节;
  • read(byte[] b),将数据读入至字节数组;

 

  创建FileInputStream的两种方法:

/*1、通过File对象构造*/
File fin=new File (“D:/abc.txt”);
FileInputStream in=new FileInputStream (fin);

/*2、直接指定文件名*/
FileInputStream in=new FileInputStream (“D:/abc.txt”);

/*创建FileOutputStream对象*/
FileOutputStream fout=new FileOutputStream (“D:/abc.txt”);

 

  4、缓冲输入输出流

  为了减少访问外存的次数,应该在一次对外数据源的访问中,读写尽可能多的数据。所以增加了缓冲机制。于是缓冲流就出现啦!!!

  FileInputStream是不带缓冲的,它的读请求会频繁与底层打交道而频繁地触发磁盘的访问,导致性能严重降低。缓冲输入流是对InputStream的装饰,提供一个缓冲区。

  FilterInputStream是装饰抽象类,为InputStream对象增加额外的功能。

  对应地,BufferedOutputStream将数据先写入缓冲流,待缓冲区满再写入设备。在数据输出完成后需要强制刷空缓冲区,调用flush()。

 

  5、数据输入输出流

  DataInputStream是包装类,提供对基本类型数据的读入的方法,需要其他的流作为输入源。一般来说,使用DataInputStream向流中写入各种类型的数据,在流的另一端用DataOutputStream从中读取对应的数据类型。

DataInputStream dataIn=new DataInputStream (new FileInputStream (“1.txt”));

  (提供5个方法,5种类型读入)

 

  6、字节数组输入输出流

  ByteArrayInputStream将一个数组当作输入的来源。

  ByteArrayOuputStream将一个数组当作流输出的目的地。它是用来缓存数据的,向它的内部缓冲区写入数据,缓冲区自动增长,当写入完成时可以从中提取数据。因此常用于存储数据便于一次写入。

  关闭ByteArrayOuputStream是无效的,关闭流后它的方法仍然可以被调用。

  使用ByteArrayInputStream则需要提供一个byte数组作为缓冲区,从流的缓冲区中读取数据。所以可以在外面包装InputStream使用它的读取方法。且通常和DataInputStream配合工作。 

 

  四、字符流

  因为Java中字符采用Unicode标准,即一个字符采用两个字节表示。为了方便文本数据的处理,引入字符流。

  1、Reader抽象类

  虽然子类必须实现的方法只有read()和close(),但一般都会重写一些方法来增强功能。

 

  2、Writer抽象类

  子类必须实现的方法仅有write()、flush()、close(),一般会重写其他一些方法。

  主要方法为5个write()和flush():

  • public void write(int c) throws IOException:将整型值的低16位写入输出流。
  • public void write(char cbuf[]) throws IOException:将字符数组cbuf[]写入输出流;
  • public void write(char buf[], int off, int len) throws IOException:将字符数粗中的从索引为off的位置处开始的len个字符写入输出流。
  • public void write(String str) throws IOException:将字符串str中的字符写入输出流;
  • public void write(String str, int off, int len) throws IOException:将字符串str中从索引off处开始的len个字符写入输出流。
  • flush():刷空输出流,并输出所有被缓存的字节。

 

  3、FileReader/FileWriter

  FileReader与FileInputStream相对应,读取字符文件,使用默认的字符编码。

  3个构造函数:

/*1、文件名作为字符串*/
FileReader f=new FileReader(“C:/temp.txt”);

/*2、构造函数将File对象作为参数*/
File file=new File (“C:/temp.txt”);
FileReader f=new FileReader (file);

/*3、构造函数将FileDescriptor对象作为参数*/
FileDescriptor fd=new FileDescriptor ();
FileReader f=new FileReader (f);

  此外,FileWriter可以在构造函数中指定append参数,若append为true,则表明对文件再次写入时,会在该文件结尾续写。

FileWriter fw=new FileWriter(String fileName, Boolean append)

 

  4、BufferedReader/BufferedWwiter

  BufferedReader从字符流中读取文本,缓冲各个字符,提供字符、数组和行的高效读取。它可以指定缓冲区的大小。

  建议用BufferedReader包装所有其它read()方法操作开销高的Reader,比如FileReader,即把其对象作为参数。

       BufferedReader in=new BufferedReader(new FileReader(“dir/abc.txt”));

 

       常用readLine(),读取一行文本,读到回车或者换行结束。

      

       BufferedWriter将文本写入字符输出流,缓冲字符以提高写出效率。通常的Writer将其输出立刻发送到目标设备,因此建议用BufferedWriter包装所有write()方法开销高的Writer(如FileWriter和OutputStreamWriter)。

       BufferedWriter提供newLine()方法,使用平台无关的行分隔符,由系统属性line.separator定义分隔符。

 

       unbuffered I/O means each read or write request is handled directly by the underlying OS.

       无缓存的IO意味着每次读或写请求都由底层操作系统直接处理。

 

  5、字节流和字符流之间的转换

  如果需要输入输出的内容是文本数据,则应该考虑使用字符流;

  如果输入输出的是二进制数据,则应该使用字节流;

  因为字节流功能更强大,而且计算机中所有的数据是二进制的。

 

       InputStreamReader和OutputStreamWriter把以字节为导向的流转换成以字符为导向的流。

       InputStreamReader是字节流通向字符流的桥梁,它使用指定的字符集读取字节并将其解码为字符。字符集可以有名称显示给定,或者使用平台默认的字符集。

       OutputStreamWriter是输出字节流通向字符流的桥梁,使用指定的字符集将要写入流中的字节流编码成字符。

       若想对InputStream和OutputStream进行字符处理,可以使用InputStreamReader和OutputStreamWriter为其加上字符处理功能,将他们转换为Reader和Writer的子类。

 

       InputStreamReader是FileReader的父类,它通常将FileInputStream作为输入,实现字节流到字符流的转换。

       若需要使用字符流从网络上读取数据,过程如下:

       网络传输—》字节流—》InputStreamReader—》字符流—》内存中的字符数据—》读取数据。

       InputStreamReader构造方法有4个:

  • Public InputStreamReader(InputStream in):创建一个使用默认字符集的转换流;
  • Public InputStreamReader(InputStream in, String charsetName):使用指定字符集的转换流
  • Public InputStreamReader(InputStream in, Charser cs):创建使用指定字符集的转换流。
  • Public InputStreamReader(InputStream in, CharsetDecoder dec):创建使用指定字符集解码器的转换流。

  OutputStreamReader类构造方法类似。

  There are two general-purpose byte-to-character "bridge" streams: InputStreamReader and OutputStreamWriter. Use them to create character streams when there are no prepackaged character stream classes that meet your needs. The sockets lesson in the networking trail shows how to create character streams from the byte streams provided by socket classes.

  

 

posted @ 2018-02-07 00:15  爆炸的果核  阅读(236)  评论(0编辑  收藏  举报