原文 链接Java 流(Stream)、文件(File)和IO
Java IO流
I/O类库中使用“流”这个抽象概念。Java对设备中数据的操作是通过流的方式。表示任何有能力产出数据的数据源对象,或者是有能力接受数据的接收端对象。“流”屏蔽了实际的I/O设备中处理数据的细节。IO流用来处理设备之间的数据传输。设备是指硬盘、内存、键盘录入、网络等。
- IO流分类
-根据数据类型的不同分为:字符流和字节流
-根据数据的流向分为:输入流和输出流
深入浅析Java中 IO流的继承结构
InputStream 与 OutputStream是一套字节输入-输出体系
Reader 与 Writer 是一套字符输入-输出体系
InputStream 与 OutputStream继承结构
InputStream和OutputStream抽象类是表示一个字节输入输出流的所有类的超类。
需要定义InputStream子类的输入流必须始终提供返回输入下一个字节的方法。
需要定义OutputStream子类输出流接受输出字节并将它们发送到某个接收器。
常用字节流类分析
- InputStream 抽象类
//从输入流中读取一定数量的字节,并将它们存储到缓冲区数组b中。实际读取的字节数作为整数返回。 | |
//此方法会阻塞,直到输入数据可用,检测到文件结尾或引发异常为止。 | |
//如果b的长度为零,则不读取字节并返回0; 否则,尝试读取至少一个字节。如果由于流位于文件末尾而没有可用的字节,则返回值 -1; 否则,至少一个字节被读取并存储到b中。 | |
//第一个字节读取存储到元素b[0] 中,下一个字节存储到b[1] 中,依此类推 | |
public int read(byte b[]) throws IOException { | |
return read(b, 0, b.length); | |
} | |
//根据后面实现,一般是一次读取一个 | |
public abstract int read() throws IOException; | |
//从off位置开始放字节 | |
public int read(byte b[], int off, int len) throws IOException; | |
//跳过并丢弃该输入流中的n字节数据。 | |
public long skip(long n) throws IOException; | |
//关闭io流 | |
public void close() throws IOException {}; | |
主要子类
1) FileInputStream:把一个文件作为InputStream,实现对文件的读取操作
public FileInputStream(String name) throws FileNotFoundException { | |
this(name != null ? new File(name) : null); | |
} | |
public FileInputStream(File file) throws FileNotFoundException; |
2) ByteArrayInputStream:把内存中的一个缓冲区作为InputStream使用
3) StringBufferInputStream:把一个String对象作为InputStream
4) PipedInputStream:实现了pipe的概念,主要在线程中使用
5) SequenceInputStream:把多个InputStream合并为一个InputStream
6) ObjectInputStream :按对象读取,对象需要实现序列化接口
2. OutputStream抽象类
//将指定的字节写入此输出流。write的一般契约是将一个字节写入输出流。 | |
public abstract void write(int b) throws IOException; | |
//从指定的字节数组中写入b.length字节。write(b) 的一般契约是,它应该与调用write(b,0,b.length) 具有完全相同的效果。 | |
public void write(byte b[]) throws IOException { | |
write(b, 0, b.length); | |
} | |
//刷新此输出流并强制写出缓冲的输出字节。flush的一般契约是,调用它表示,如果先前写入的任何字节已被输出流的实现缓冲,则应立即将这些字节写入其预期目标。 | |
public void flush() throws IOException { | |
} | |
public void close() throws IOException { | |
} | |
主要的子类
- ByteArrayOutputStream:把信息存入内存中的一个缓冲区中
- FileOutputStream:把信息存入文件中
//是否追加 | |
public FileOutputStream(String name, boolean append); |
- PipedOutputStream:实现了pipe的概念,主要在线程中使用
- SequenceOutputStream:把多个OutStream合并为一个OutStream
- ObjectOutputStream :按对象输出,对象需要实现序列化接口
重点:缓冲输入输出流 BufferedInputStream/ BufferedOutputStream
BufferedInputStream:当向缓冲流写入数据时候,数据先写到缓冲区,待缓冲区写满后,系统一次性将数据发送给输出设备。
BufferedOutputStream :当从向缓冲流读取数据时候,系统先从缓冲区读出数据,待缓冲区为空时,系统再从输入设备读取数据到缓冲区。
BufferedInputStream
//默认大小,最大是Integer.MAX_VALUE - 8; | |
private static int DEFAULT_BUFFER_SIZE = 8192; | |
//缓冲区 | |
protected volatile byte buf[]; | |
public BufferedInputStream(InputStream in) { | |
this(in, DEFAULT_BUFFER_SIZE); | |
} | |
public BufferedInputStream(InputStream in, int size) { | |
super(in); | |
if (size <= 0) { | |
throw new IllegalArgumentException("Buffer size <= 0"); | |
} | |
buf = new byte[size]; | |
} | |
//具体实例 | |
File srcFile=new File("hello.txt"); | |
File srcFile1=new File("hello2.txt"); | |
FileInputStream fis=new FileInputStream(srcFile); | |
FileOutputStream fw=new FileOutputStream(srcFile1); | |
BufferedInputStream bis=new BufferedInputStream(fis); | |
BufferedOutputStream bos=new BufferedOutputStream(fw); | |
byte[] ch=new byte[5]; | |
int len; | |
while((len=bis.read(ch))!=-1) | |
{ | |
bos.write(ch,0,len); | |
} | |
bos.close(); | |
bis.close(); |
BufferedOutputStream
//其他类似 | |
public synchronized void flush() throws IOException { | |
flushBuffer(); | |
out.flush(); | |
} | |
//刷新此缓冲的输出流。这将强制将任何缓冲的输出字节写入基础输出流。 |
小结
Stream都是针对字节流的,BufferedOutputStream和BufferedOutputStream类BufferedOutputStream:缓冲字节输出流是一个高级流,与其他低级流配合使用。它们内部有一个缓冲区,用来提高处理效率。读取或输出数据时,先存放在缓冲区,当缓冲区满时,或者调用flush方法,缓冲输出流会将数据写出。对于小文件可能看不到性能的提升。但是文件稍微大一些的话,就可以看到实质的性能提升了。
Writer和Reader继承结构
Writer用于写入字符流的抽象类。子类必须实现的唯一方法是write(char[],int,int),flush() 和close()。
Reader用于读取字符流的抽象类。子类必须实现的唯一方法是read(char[],int,int) 和close()。
常用Reader流
//用于同步此流上的操作的对象。为了提高效率,字符流对象可以使用除其自身以外的对象来保护关键部分 | |
protected Object lock; | |
//构造函数 | |
protected Reader(Object lock) ; | |
protected Reader() { | |
this.lock = this; | |
} | |
//没什么特别的 | |
abstract public void close() throws IOException; | |
abstract public int read(char cbuf[], int off, int len); | |
public int read(char cbuf[]) throws IOException; | |
private char skipBuffer[] = null; | |
//跳过字符。此方法将阻塞,直到某些字符可用,出现I/O错误或到达流结束为止。 | |
public long skip(long n) throws IOException; | |
子类:
(1) 用指定字符数组作为缓存参数:CharArrayReader(char[])
将字符数组作为输入流:public CharArrayReader(char buf[], int offset, int length)
2) CharArrayReader:此类实现了一个字符缓冲区,可以用作字符输入流
3) StringReader :源为字符串的字符流
4) InputStreamReader
InputStreamReader是从字节流到字符流的桥梁: 它读取字节并使用指定的字符集将它们解码为字符。
5) FilterReader: 允许过滤字符流
protected filterReader(Reader r);
6) BufferReader :接受Reader对象作为参数,并对其添加字符缓冲器,使用readline()方法可以读取一行。
Public BufferReader(Reader r);
String readLine(boolean ignoreLF)
ignoreLF – If true, the next '\n' will be skipped
7) FileReader 用于读取字符文件的便利类。此类的构造函数假定默认字符编码和默认字节缓冲区大小是适当的。需要指定的化需要 InputStreamReader on a FileInputStream.
Write常用流
//用于保存字符串和单个字符的写入的临时缓冲区 | |
private char[] writeBuffer; | |
private static final int WRITE_BUFFER_SIZE = 1024; | |
protected Object lock; | |
//Writes an array of characters. | |
public void write(char cbuf[]) throws IOException { | |
write(cbuf, 0, cbuf.length); | |
} | |
abstract public void write(char cbuf[], int off, int len) throws IOException; | |
public void write(String str) throws IOException { | |
write(str, 0, str.length()); | |
} | |
//追加 | |
public Writer append(CharSequence csq) throws IOException { | |
if (csq == null) | |
write("null"); | |
else | |
write(csq.toString()); | |
return this; | |
} | |
abstract public void flush() throws IOException; | |
abstract public void close() throws IOException; |
子类:
1) FileWrite: Convenience class for writing character files.
2) chararrayWrite:This class implements a character buffer that can be used as an Writer.
3) PrintWrite:生成格式化输出
public PrintWriter(outputstream os);
4) filterWriter:用于写入过滤字符流
protected FilterWriter(Writer w);
5) PipedWriter:写入管道
6) StringWriter:字符串写入
7)BufferedWriter:将文本写入字符输出流,缓冲字符,以便有效地写入单个字符,数组和字符串。
public void newLine()写入一个行分隔符。
//常用法 | |
//不存在就创建 | |
File file=new File("hello1.txt"); | |
FileWriter fw=new FileWriter(file); | |
fw.write("asdfghjkl;\n"); | |
fw.write("12231232123"); | |
fw.close(); | |
小结
对于字符流,如果对于大文件推荐使用缓存BufferedWriter,和BufferedReader。
总结
- 需要较高的读写速度
使用缓存BufferedInputStream, BufferedOutputStream,( 字节流 ) BufferedReader, BufferedWriter( 字符流 ),注意:当缓冲区未写满的情况下,需要flush去清空缓存写入。
当然close函数有运行flush,读取的化会返回读取长度。 - 对于文件操作
FileInputStream, FileOutputStream, ( 字节流 )FileReader, FileWriter( 字符 ) - 网络数据流
InputStream, OutputStream,( 字节流 ) Reader, Writer( 字符流 ) - 特殊需要:
从 Stream 到 Reader,Writer 的转换类: InputStreamReader, OutputStreamWriter
对象输入输出: ObjectInputStream, ObjectOutputStream
进程间通信: PipeInputStream, PipeOutputStream, PipeReader, PipeWriter