一. I/O流概述
输入输出处理是程序设计中非常重要的一部分,从键盘中读数据或从文件中读写数据等等。
java把这些不同类型的输入、输出源抽象为流(stream),用统一接口来表示,从而使程序简单明了。
I/O中的Exception
进行I/O操作时可能会产生I/O例外,属于非运行时例外,应该在程序中处理。
如:FileNotFoundException, EOFException, IOException
java.io包中有关文件处理包括:
类:File、FileInputStream、FileOutputStream、RamdomAccessFile和FileDescription
接口:FilenameFilter
1. 字节流:
从InputStream和OutputStream派生出来的一系列类,以字节(byte)为基本处理单位
2. 字符流:
从Reader和Writer派生出来的一系列类,以16位的Unicode码表示的字符为基本处理单位
3. 对象流:
ObjectInputStream、ObjectOutputStream
4. 其他
文件处理:
文件处理:
File、RandomAccessFIle
接口:
DataInput、DataOutput、ObjectInput、ObjectOutput
二. 文件描述
类File:并不代表磁盘上的文件,可以理解为文件的路径,但是比String形式的路径更为安全。
1)文件或目录的生成
public File(String path); // 如果path是路径,则该File对象表示的是目录;如果path是文件名,则该表示的是文件
public File(String path, String name); // path是路径名,name是文件名
public File(File dir, String name); // dir是路径名,name是文件名
2)文件名的处理
String getName(); // 得到一个文件的名称(不包括路径)
String getPath(); // 得到一个文件的路径名
String getAbsolutePath(); // 得到一个文件的绝对路径名
String getParent(); // 得到一个文件的上一级目录名
String renameTo(File newName); // 将当前文件名更名为给定文件的完整路径
3)文件属性测试
boolean exists(); // 测试当前FIle对象所指示的文件是否存在
boolean canWrite(); // 测试当前文件是否可写
boolean canRead(); // 测试当前文件是否可读
boolean isFile(); // 测试当前文件是否是文件
boolean isDirectory; // 测试当前文件是否是目录
4)普通文件信息和工具
long lastModified(); // 得到文件最近一次修改的时间
long length(); // 得到文件的长度,以字节为单位
boolean delete(); // 删除当前文件
5)目录操作
boolean mkdir(); // 根据当前对象生成以一个由该对象指定的路径
String list(); // 列出当前目录下的文件。
// File假如是一个Directory,可以通过list()方法得到这个目录下所有的文件和目录的名称数组。
// 一种是没有参数,一种是实现FilenameFilter接口的参数。
FilenameFilter接口,能够过滤得到指定类型的文件或者目录,其中必须重写accept(File file,String path)方法
eg: 列出C:\MyProjects下后缀为.java的文件
1 import java.io.*;
2
3 public class FileFilterTest {
4 public static void main(String args[]) {
5 File dir = new File("C://MyProjects"); // 用File对象表示一个目录
6 Filter filter = new Filter("java"); // 生成一个名为java的过滤器
7 System.out.println("list java files in directory" + dir);
8
9 String files[] = dir.list(filter); // 列出目录dir下,文件名后缀名为java的所有文件
10
11 for (int i = 0; i < files.length; i++) {
12 File f = new File(dir, files[i]); // 为目录dir下的文件或目录创建一个File对象
13 if (f.isFile())
14 System.out.println("file " + f);
15 else
16 System.out.println("sub dirctory " + f);
17 }
18 }
19 }
20
21 class Filter implements FilenameFilter { // 必须重写accept(File file,String path)方法
22 String extent;
23
24 Filter(String extent) {
25 this.extent = extent;
26 }
27
28 public boolean accept(File dir, String name) {
29 return name.endsWith("." + extent); //返回文件的后缀名
30 }
31 }
二. I/O流详述
1. 字节流
InputStream类
a) 从流中个读取数据:
int read(); // 读取一个字节,返回实际所读字节
int read(byte b[]); // 读取字节数为b的长度,并存放在字节数组b中,返回值为实际读取的字节的数量
int read(byte b[], int off, int len); // 读取len个字节,放置在以下标off开始的字节数组b中,返回值为实际读取的字节的数量
int available(); // 返回值为流中尚未读取的字节的数量
long skip(long n); // 读指针跳过n个字节不读,返回值为实际跳过的字节数量
b) 关闭流:
close(); // 流操作完毕后必须关闭
c) 使用输入流中的标记:
void mark(int readlimit); // 记录当前读指针所在位置,readlimit表示读指针读出readlimit个字节后标记的指针位置才失效
void reset(); // 把读指针重新指向用mark方法所记录的位置
boolean markSupported(); // 当前的流是否支持读指针的记录功能
OutputStream类
a) 输出数据:
void write(int b); // 往流中写一个字节b
void write(byte b[]); // 往流中写一个字节数组b
void write(byte b[], int off, int len); // 把字节数组b中下标off开始,长度为len的字节写入流中
flush(); // 刷空输出流,并输出所有被缓存的字节,由于某些流支持缓存的功能,该方法将把缓存中所有内容强制输出到流中
b) 关闭流:
close(); // 流操作完毕后必须关闭
过滤流(包装流)
过滤流在读写数据的同时可以对数据进行处理,它提供了同步机制,使得某一时刻只有一个线程可以访问一个I/O流
防止多个线程同时对一个I/O流进行操作带来的意想不到的结果。
类FilterInputStream和FilterOutputStream分别作为所有过滤输入流和输出流的父类
a) 使用过滤流的步骤:
连接到某个输入输出流上,通过在构造方法的参数中指定所要连接的输入输出流上来实现
FilterInputStream(InputStream in);
FilterOutputStream(OutputStream out);
b) 几种常见的过滤流
BufferedInputStream和BufferedOutputStream 缓冲流,用于提高输入输出处理的效率
DataInputStream和DataOutputStream 不仅能读写数据流,而且读写各种java语言的基本类型
LineNumberInputStream 除了对输入处理的支持外,可以记录当前的行号
PushbackInputStream 提供了一个方法可以把刚读的字节退回到输入流中,以便重新再读一遍
PrintStream 打印流的作用是吧java语言的内构类型以其字符表示形式动到相应的输出流
2. 字符流
字符流的处理
java提供16位Unicode码表示的字符流的类,即以Reader和Writer为基类派生出的一系列类
Reader和Writer:这两个类是抽象类,只是提供了一系列用于字符流处理的接口,不能生成实例。
Reader类:是处理所有字符流输入类的父类
a) 读取字符
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个字符,存入off开始的cbuf中,返回实际读取的 // 的字数,必须由子类实现
b) 标记流
public boolean markSupported(); // 判断当前流是否支持做标记
public void mark(int readAheadLimit) throws IOException; // 给当前流作标记,最多支持readAheadLimit个字符的回溯
public void reset() throws IOException; // 将当前流重置到做标记处
c) 关闭流
public abstract void close() throws IOExeption;
Writer类:是处理所有字符流输出类的父类
a) 向输出流写入字符
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); // 将字符数组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个字符写入输出流
flush() 刷空输出流,并输出所有被缓冲的字节
b) 关闭流
public abstract void close() throws IOException;
java.io包中用于处理字符流的最基本的类:InputStreamReader OutputStreamWriter,此外还有FileReader和FileWriter
a) 生成流对象
public InputStreamReader(InputStream in); // in是字节流,即将字节流转换成字符流来处理
public InputStreamReader(InputStream in, String enc) throws UnsupportedEncodingExceptio; // enc是编码方式:ISO8859-1,UTF-8,UTF-16
public OutputStreamWriter(OutputStream out); // out是字节流
public OutputStreamWriter(OutputStream out, String enc) throws UnsupportedEncodingException; // enc是编码方式
b) 读写字符
基本与Reader和Writer一致
c) 获取当前编码方式
public String getEncoding();
d) 关闭流
public void close() throws IOException;
BufferedReader和BufferedWriter
a) 生成流对象
public BufferedReader(Reader in);
public BufferedReader(Reader in, int sz); // sz为缓冲区的大小
public BufferedWriter(Writer out);
public BufferedWriter(Writer out, int sz);
b) 读写字符
增加对整行字符的处理
public String readline() throws IOException; // 读一行字符
public void newLine() throws IOException; // 写一行字符
1 // 从键盘读入数字,并输出
2 import java.io.*;
3
4 public class NumberInput {
5 public static void main(String args[]) {
6 try {
7 InputStreamReader ir;
8 BufferedReader in;
9 ir = new InputStreamReader(System.in);
10 // 从键盘接受一个字符串的输入,并创建了一个字符输入流的对象
11 in = new BufferedReader(ir); // 用字符输入流ir创建一个BufferedReader对象
12 String s = in.readLine(); // 从输入流in中读入一行
13 System.out.println("Input value is: " + s);
14 int i = Integer.parseInt(s); // 转换成int
15 i *= 2;
16 System.out.println("Input value changed after doubled: " + i);
17 }
18 catch (IOException e) {
19 System.out.println(e);
20 }
21 }
22 }
3. 对象流
串行化
对象通过描述自己状态的数值来记录自己,这个过程叫对象的串行化(Serialization)
a) 串行化方法:
java.io包中,接口Serializable用来作为对象串行化的工具,只有实现了Serializable的对象才可以被串行化
串行化步骤:
1 1. 定义一个可串行化的对象 2 3 public class Student implements Serializable {...} 4 5 2. 通过ObjectInputStream和ObjectOutputStream这两个对象流存取可串行化对象 6 7 Student stu = new Student(); 8 9 FileOutputStream fo = new FileOutputStream("data.ser"); 10 11 ObjectOutputStream so = new ObjectOutputStream(fo); 12 13 try { 14 15 so.writeObject(stu); 16 17 so.close(); 18 19 } catch (IOException e) { 20 21 System.out.println(e); 22 23 } 24 25 FileInputStream fi = new FileInputStream("data.ser"); 26 27 ObjectInputStream si = new ObjectInputStream(fi); 28 29 try { 30 31 stu = (student)si.readObject(); 32 33 si.close(); 34 35 } catch (IOException e) { 36 37 System.out.println(e); 38 39 }
注意事项:
1. 只能保存非静态成员变量,不能保存任何成员方法和静态成员变量,保存的只是变量的值,对于变量的任何修饰符都无法保存
2. transient关键字,对于某些瞬时对象(Thread对象,FileInputStream对象),无法保存,必须用transient关键字表明
3. 定制串行化,缺省机制为按名称升序,想定制就要重写writeObject()和readObject()
4. 其他常用的流
管道流
用来把一个程序、线程或代码块的输出连接到另一个程序、线程或代码块的输入
在使用管道前,管道输出流和管道输入流必须进行连接。
a) 构造方法连接
PipedInputStream(PipedOutputstream src);
PipedOutputStream(PipedInputStream snk);
b) connect方法进行连接
类PipedInputStream中定义为:
void connect(PipedOutputSream src);
类PipedOutputStream中定义为:
void connect(PipedInputSream snk);
小结:
字节流:
抽象类 InputStream OutputStream
跟数据源直接接触的类: FileInputStream FileOutputStream
装饰类: BufferedInputStream: 提供了缓冲功能 BufferedOutputStream: 提供缓冲功能
重要方法:
read();
read(byte[] b);
read(byte[] b, int off, int len);
write(int b);
write(byte[] b);
write(byte[] b, int off, int len);
字符流:
抽象类 Reader Writer
跟数据源直接接触的类 FileReader FileWriter
装饰类 BufferedReader: 缓冲,readLine() BufferedWriter: 缓冲
重要方法:
read(char[] cbuf);
read(char[] cbuf, int off, int len);
read(CharBuffer target);
write(char[] cbuf);
write(char[] cbuf, int off, int len);
write(int c);
write(String str);
write(String str, int off, int len);
对象流
需要被序列化的对象必须实现Serializable接口
调用ObjectOutputStream的writeObject()方法,通过装饰FileOutputstream
调用ObjectInputStream的readObject()方法,通过装饰FileInputStream