一、概要
Java I/O主要包括如下几个层次,包含三个部分:
- 流式部分――IO的主体部分;
- 非流式部分――主要包含一些辅助流式部分的类,如:File类、RandomAccessFile类和FileDescriptor等类;
- 其他类--文件读取部分的与安全相关的类,如:SerializablePermission类,以及与本地操作系统相关的文件系统的类,如:FileSystem类和Win32FileSystem类和WinNTFileSystem类。
主要的类如下:
- File(文件特征与管理):用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等。
- InputStream(二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。
- OutputStream(二进制格式操作):抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。
- Reader(文件格式操作):抽象类,基于字符的输入操作。
- Writer(文件格式操作):抽象类,基于字符的输出操作。
- RandomAccessFile(随机文件操作):一个独立的类,直接继承至Object.它的功能丰富,可以从文件的任意位置进行存取(输入输出)操作。
Java中IO流的体系结构如图:
Java流类的类结构图:
二、字节流
2.1 输入字节流 InputStream
基本输入字节流:
装饰输入字节流:
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
基本输出字节流:
装饰输出字节流:
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
在上面的继承关系图中可以看出:
- 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
在上面的关系图中可以看出:
- 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)
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