JAVA基础IO介绍
wilder
本文主要翻译自sun的tutotrial文档,详细内容请参见英文原文
一个I/O流表示一个输出源一个输入目的地,流可以处理多种类型的数据源/数据目标:如文件,设备,其它程序甚至内存数组.
流支持多种不同类型的数据,包括简单的byte,原始数据单位,本地字符串以及对象,一些流只是简单传递数据,一些可以使用有效的手段做一些转换处理
不用关心它们内部如何实现,所有的流对于程序来讲表现相同的模式:流是一序列的数据,程序使用输入流从源头读取数据,如下面所示:
程序使用输出流向目标写入数据,如下面所示:
在本文中我们将看到使用流操纵各种不同的数据,从原始数据到高级对象.
上图中的数据源和数据目标可以是任何数据,这当然包括磁盘文件,并且可以是其它程序,外围设备,网络套接字或数组,在接下来的章节中我们将使用最基础的字节流byte流来展示一些基础的io操作,比如说输入,我们会用一个示例文件
它的内容如下:
In Xanadu did Kubla Khan
A stately pleasure
-
dome decree:
Where Alph, the sacred river, ran
Through caverns measureless to man
Down to a sunless sea.
In Xanadu did Kubla Khan
A stately pleasure-dome decree:
Where Alph, the sacred river, ran
Through caverns measureless to man
Down to a sunless sea.
|
注意read() 方法返回整数值,如果-1表示已经读取到了流的结束
注意流使用完了一定要关闭,否则引起很严重的资源泄露.
下面来看一下使用字符流CharacterStream,
在java平台中,存贮字符数据使用unicode编码,字符流自动的使用这一格式转换,从数据读取或写出,自动将unicode编码转换成本地字符集,在西方本地字符集通常是8个bit ASCII超集
在大部分程序中,使用字符流没有使用字节流复杂,输入输出流类自动的将数据转换成本地字符集,一个程序使用字符流代替字节流可以自动的转换适应到本地字符集适应国际化的需要,所有的工作不需要额外的编码工作.
字符流类都是从Reader,Writer继承过来的,同字节流一样,我们看一下文件操作的字符流
import
java.io.FileReader;
import
java.io.FileWriter;
import
java.io.IOException;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
public
class
CopyCharacters
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public static void main(String[] args) throws IOException ...{
FileReader inputStream = null;
FileWriter outputStream = null;
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
try ...{
inputStream = new FileReader("xanadu.txt");
outputStream = new FileWriter("characteroutput.txt");
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
int c;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
while ((c = inputStream.read()) != -1) ...{
outputStream.write(c);
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
} finally ...{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if (inputStream != null) ...{
inputStream.close();
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if (outputStream != null) ...{
outputStream.close();
}
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
和上一个例子差不多,只不过这里使用的是FileReader和FileWriter,而前者使用的是FileInputStream和FileOutputStream,值得注意的是两个例子都是将数据读到一个int变量中,但是这里,此int变量的最后16个bite存放的是一个character数据,而前者int变量最后8bit存放的是一个byte
字符流经常被包装成字节流使用
InputStreamReader,OutputStreamWriter
行为导向的字符流
经常处理文本时,是一行一行的处理
缓冲流
大部分例子我们看到的是使用无缓冲的io操作,这意味着每一个读写都是直接handled到操作系统,没有延迟的.这些使得程序变得非常低效,因为每一个请求经常会触发磁盘访问,网络激活及其它相当费时的操作开销.
为了减少这种开销,java实现了缓存io流,从内存读写的流.读取时当内存为空时者才会触发本地调用,写入时,只有当内存满了之后才会触发本地调用,程序可以将一个非缓冲的流包装成一个缓冲的流,在上面例子中我们经常使用的BufferedReader, BufferedWriter
这里有四种类型的缓冲流
后面主要针对字符流
缓存的冲洗 Flush Buffered Stream
经常因为某些原因我们不会等到buffer full才把数据同步到设备(文件,网络等)
这时我们 需要做flush操作
一些缓冲流支持自动冲洗,只需要指定一个可选的构造参数,当自动冲洗被激活时,一些特定的事件会触发缓冲流的冲洗,如PrinterWtriter缓冲流在每次调用println或format时
如果手工冲洗,调用flush就行了这个方法在每一个流上都有,但是只有缓冲流才会有效果.