一、概要

  Java I/O主要包括如下几个层次,包含三个部分:

  • 流式部分――IO的主体部分;
  • 非流式部分――主要包含一些辅助流式部分的类,如:File类、RandomAccessFile类和FileDescriptor等类;
  • 其他类--文件读取部分的与安全相关的类,如:SerializablePermission类,以及与本地操作系统相关的文件系统的类,如:FileSystem类和Win32FileSystem类和WinNTFileSystem类。

  主要的类如下:

  • File(文件特征与管理):用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等。
  • InputStream(二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。
  • OutputStream(二进制格式操作):抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。
  • Reader(文件格式操作):抽象类,基于字符的输入操作。
  • Writer(文件格式操作):抽象类,基于字符的输出操作。
  • RandomAccessFile(随机文件操作):一个独立的类,直接继承至Object.它的功能丰富,可以从文件的任意位置进行存取(输入输出)操作

   Java中IO流的体系结构如图:

    

java io流练习题 java io流的层次结构_java io

  Java流类的类结构图:

    

java io流练习题 java io流的层次结构_java io_02

二、字节流

2.1 输入字节流 InputStream

  基本输入字节流:

java io流练习题 java io流的层次结构_io_03

   装饰输入字节流:

java io流练习题 java io流的层次结构_字节流_04

   InputStream中的三个基本的读方法

  • abstract int read() :读取一个字节数据,并返回读到的数据,如果返回-1,表示读到了输入流的末尾。
  • int  read(byte[] b) :将数据读入一个字节数组,同时返回实际读取的字节数。如果返回-1,表示读到了输入流的末尾。
  • int  read(byte[] b, int off, int len) :将数据读入一个字节数组,同时返回实际读取的字节数。如果返回-1,表示读到了输入流的末尾。off指定在数组b中存放数据的起始偏移位置;len指定读取的最大字节数。

    流结束的判断:方法read()的返回值为-1时;readLine()的返回值为null时。
  

  其它方法

  • long skip(long n):在输入流中跳过n个字节,并返回实际跳过的字节数。
  • int available() :返回在不发生阻塞的情况下,可读取的字节数。
  • void close() :关闭输入流,释放和这个流相关的系统资源。
  • void mark(int readlimit) :在输入流的当前位置放置一个标记,如果读取的字节数多于readlimit设置的值,则流忽略这个标记。
  • void reset() :返回到上一个标记。
  • boolean markSupported() :测试当前流是否支持mark和reset方法。如果支持,返回true,否则返回false。

 2.2 输出字节流 OutputStream

   基本输出字节流:

java io流练习题 java io流的层次结构_io_05

  装饰输出字节流:

java io流练习题 java io流的层次结构_java io流练习题_06

  OutputStream中的三个基本的读方法

  • abstract void write(int b):往输出流中写入一个字节。
  • void write(byte[] b) :往输出流中写入数组b中的所有字节。
  • void write(byte[] b, int off, int len) :往输出流中写入数组b中从偏移量off开始的len个字节的数据。

  其它方法

  • void flush() :刷新输出流,强制缓冲区中的输出字节被写出。
  • void close() :关闭输出流,释放和这个流相关的系统资源。

三、字符流  

 3.1 输入字符流 Reader

   

java io流练习题 java io流的层次结构_java io流练习题_07

  在上面的继承关系图中可以看出:

  • Reader是所有的输入字符流的父类,它是一个抽象类。
  • CharReader、StringReader是两种基本的介质流,它们分别将Char数组、String中读取数据。PipedReader是从与其它线程共用的管道中读取数据。
  • BufferedReader很明显就是一个装饰器,它和其子类负责装饰其它Reader对象。
  • FilterReader是所有自定义具体装饰流的父类,其子类PushbackReader对Reader对象进行装饰,会增加一个行号。
  • InputStreamReader是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream转变为Reader的方法。我们可以从这个类中得到一定的技巧。Reader中各个类的用途和使用方法基本和InputStream中的类使用一致。后面会有Reader与InputStream的对应关系。

   主要方法:

  • public int read() throws IOException; //读取一个字符,返回值为读取的字符 
  • public int read(char cbuf[]) throws IOException; /*读取一系列字符到数组cbuf[]中,返回值为实际读取的字符的数量*/ 
  • public abstract int read(char cbuf[],int off,int len) throws IOException; /*读取len个字符,从数组cbuf[]的下标off处开始存放,返回值为实际读取的字符数量,该方法必须由子类实现*/ 

  3.2 输出字符流 Writer

   

java io流练习题 java io流的层次结构_字节流_08

  在上面的关系图中可以看出:

  • Writer是所有的输出字符流的父类,它是一个抽象类。
  • CharArrayWriter、StringWriter是两种基本的介质流,它们分别向Char数组、String中写入数据。PipedWriter是向与其它线程共用的管道中写入数据,
  • BufferedWriter是一个装饰器为Writer提供缓冲功能。
  • PrintWriter和PrintStream极其类似,功能和使用也非常相似。
  • OutputStreamWriter是OutputStream到Writer转换的桥梁,它的子类FileWriter其实就是一个实现此功能的具体类(具体可以研究一SourceCode)。功能和使用和OutputStream极其类似.

   主要方法:

  • public void write(int c) throws IOException; //将整型值c的低16位写入输出流
  • public void write(char cbuf[]) throws IOException; //将字符数组cbuf[]写入输出流
  • public abstract void write(char cbuf[],int off,int len) throws IOException; //将字符数组cbuf[]中的从索引为off的位置处开始的len个字符写入输出流
  • public void write(String str) throws IOException; //将字符串str中的字符写入输出流
  • public void write(String str,int off,int len) throws IOException; //将字符串str 中从索引off开始处的len个字符写入输出流 

四、字符流和字节流的转换

  OutputStreamWriter(OutStreamout):将字节流以字符流输出。  字符到字节的桥梁

  InputStreamReader(InputStream in):将字节流以字符流输入。  字节到字符的桥梁

BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File("D:/1.jpg")),"utf-8"));

五、非流式文件类--File类

   File类是对文件系统中文件以及文件夹进行封装的对象,可以通过对象的思想来操作文件和文件夹。File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。 

  构造函数:

  • File (String   pathname)   
  • 例:File  f1=new File("FileTest1.txt"); //创建文件对象f1,f1所指的文件是在当前目录下创建的FileTest1.txt
  • File (String  parent  ,  String child)
  • 例:File f2=new  File(“D:\\dir1","FileTest2.txt") ;//  注意:D:\\dir1目录事先必须存在,否则异常
  • File (File    parent  , String child)
  • 例:File  f4=new File("\\dir3");  File  f5=new File(f4,"FileTest5.txt");  //在如果 \\dir3目录不存在使用f4.mkdir()先创建

  一个对应于某磁盘文件或目录的File对象一经创建, 就可以通过调用它的方法来获得文件或目录的属性。   

    1)public boolean exists( ) 判断文件或目录是否存在
       2)public boolean isFile( ) 判断是文件还是目录 
       3)public boolean isDirectory( ) 判断是文件还是目录
       4)public String getName( ) 返回文件名或目录名
       5)public String getPath( ) 返回文件或目录的路径。
       6)public long length( ) 获取文件的长度 
       7)public String[ ] list ( ) 将目录中所有文件名保存在字符串数组中返回。 

       File类中还定义了一些对文件或目录进行管理、操作的方法,常用的方法有:
       1) public boolean renameTo( File newFile );    重命名文件
       2) public void delete( );   删除文件
       3) public boolean mkdir( ); 创建目录

 六、RandomAccessFile类

  文件的分隔与合并,随机访问文件。

 

  1.    该对象只能操作文件,所以构造函数接收两种类型的参数:a.字符串文件路径;b.File对象。

 

  2.    该对象既可以对文件进行读操作,也能进行写操作,在进行对象实例化时可指定操作模式(r,rw)

java io流练习题 java io流的层次结构_java io流练习题_09

java io流练习题 java io流的层次结构_io_10

1 public static void main(String[] args)
 2     {
 3         try
 4         {
 5             insert("d:/out.txt",5,"插入的内容");
 6         }
 7         catch (IOException e)
 8         {
 9             e.printStackTrace();
10         }
11     }
12     
13     private static void insert(String fileName,long pos,String content) throws IOException
14     {
15         //创建临时空文件
16         File tempFile = File.createTempFile("temp",null);
17         //在虚拟机终止时,请求删除此抽象路径名表示的文件或目录
18         tempFile.deleteOnExit();
19         FileOutputStream fos = new FileOutputStream(tempFile);
20         
21         RandomAccessFile raf = new RandomAccessFile(fileName,"rw");
22         raf.seek(pos);
23         byte[] buffer = new byte[4];
24         int num = 0;
25         while(-1 != (num = raf.read(buffer)))
26         {
27             fos.write(buffer,0,num);
28         }
29         raf.seek(pos);
30         raf.write(content.getBytes());
31         FileInputStream fis = new FileInputStream(tempFile);
32         while(-1 != (num = fis.read(buffer)))
33         {
34             raf.write(buffer,0,num);
35         }
36     }

指定位置插入内容

七、System类对IO的支持

  针对一些频繁的设备交互,Java语言系统预定了3个可以直接使用的流对象,分别是:

   System.in(标准输入),通常代表键盘输入。其数据类型为InputStream

   System.out(标准输出):通常写往显示器。其数据类型为PrintStream

   System.err(标准错误输出):通常写往显示器。其数据类型为PrintStream