Java IO工作机制分析
Java的IO类都在java.io包下,这些类大致可分为以下4种:
- 基于字节操作的 I/O 接口:InputStream 和 OutputStream
- 基于字符操作的 I/O 接口:Writer 和 Reader
- 基于磁盘操作的 I/O 接口:File
- 基于网络操作的 I/O 接口:Socket
1 IO类库的基本结构
1.1 基于字节操作的IO接口
基于字节操作的IO接口分别是InputStream和OutputStream,InputStream的类结构图如下所示:

同InputStream类似,OutputStream类也有着相同的类结构图。

关于各个子类的使用可以参考JDK 的 API 说明文档,这里我们需要注意的是:操作数据的方式是可以组合的,如下所示:
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("h:\\haha.txt"), "utf-8");
从上面代码可以看出,InputStreamReader可以从FileInputStream中读取数据,从源码中可以看出来,其实不仅是InputStreamReader,所有的IO类都可以以这种方式来组合使用。

还有一点需要注意的是必须制定流最终写入到什么地方,是磁盘还是网络,从OutputStream类图中可以看出,写入网络中实际也是写文件操作,只不过底层是通过网络传输了。
1.2 基于字符的IO操作接口
不管是磁盘还是网络数据传输,都是以字节为单位的,但是程序中一般常见的数据操作都是以字符为单位的(Java中char占用2字节,C/C++中 char占用1字节),这就需要我们有一个操作字符的IO接口,来处理字符与字节见的编码转换问题,也就是Write和Reader接口及其实现类,他们 二者的类接口图如下:


读字符接口Reader的最主要操作方法为read(),其读取字符并返回读取的字符数,不管是 Writer 还是 Reader 类它们都只定义了读取或写入的数据字符的方式,也就是怎么写或读,但是并没有规定数据要写到哪去(比如磁盘或者网络)。
1.3 字节与字符的转化接口
有时数据持久化和网络传输是以字节进行的,所有需要字节和字符之间的相互转换。

/**
* 使用FileReader进行读取文件
*/
@Test
public void testFileReader() throws IOException {
FileReader fileReader = new FileReader("h:\\haha.txt");
char[] buff = new char[512];
StringBuffer stringBuffer = new StringBuffer(); while (fileReader.read(buff) > 0) {
stringBuffer.append(buff);
}
fileReader.close(); System.out.print(stringBuffer.toString());
} /**
* 使用FileReader进行读取文件,然后FileWriter写入另一个文件
*/
@Test
public void testFileReaderAndFileWriter() throws IOException {
FileReader fileReader = new FileReader("h:\\haha.txt");
char[] buff = new char[512];
StringBuffer stringBuffer = new StringBuffer(); while (fileReader.read(buff) > 0) {
stringBuffer.append(buff);
}
System.out.println(stringBuffer.toString()); FileWriter fileWriter = new FileWriter("h:\\haha2.txt");
fileWriter.write(stringBuffer.toString().trim()); fileWriter.close();
System.out.println("写入文件成功");
}
/**
* 使用InputStreamReader进行读取文件
*/
@Test
public void testInputStreamReader() throws IOException {
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("h:\\haha.txt"), "utf-8");
char[] buff = new char[512];
StringBuffer stringBuffer = new StringBuffer(); while (inputStreamReader.read(buff) > 0) {
stringBuffer.append(buff);
}
System.out.println(stringBuffer.toString());
} @Test
public void testIntputStream2() throws IOException {
InputStreamReader inputStreamReader = new InputStreamReader(new StringBufferInputStream("hello world"));
char[] buff = new char[512]; int n = inputStreamReader.read(buff);
System.out.println(n);
System.out.println(buff);
} /**
* 使用inputStreamReader进行读取文件,然后OutputStreamWriter写入另一个文件
*/
@Test
public void testOutputStreamWriter() throws IOException {
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("h:\\haha.txt"), "utf-8");
char[] buff = new char[512];
StringBuffer stringBuffer = new StringBuffer(); while (inputStreamReader.read(buff) > 0) {
stringBuffer.append(buff);
}
System.out.println(stringBuffer.toString()); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("h:\\haha2.txt"), "utf-8");
outputStreamWriter.write(stringBuffer.toString().trim());
outputStreamWriter.close();
}
注意:FileReader类继承了InputStreamReader,FileReader读取文件流,通过StreamDecoder解码成char,其解码字符集使用的是默认字符集。在Java中,我们应该使用File对象来判断某个文件是否存在,如果我们用FileOutputStream或者FileWriter打开,那么它肯定会被覆盖。
2 同步和异步、阻塞和非阻塞
同步和异步是针对IO来说的。所谓同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列。要么成功都成功,失败都失败,两个任务的状态可以保持一致。而异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列。我们可以用打电话和发短信来很好的比喻同步与异步操作。
阻塞和非阻塞是针对CPU来说的。阻塞与非阻塞主要是从 CPU 的消耗上来说的,阻塞就是 CPU 停下来等待一个慢的操作完成 CPU 才接着完成其它的事。非阻塞就是在这个慢的操作在执行时 CPU 去干其它别的事,等这个慢的操作完成时,CPU 再接着完成后续的操作。虽然表面上看非阻塞的方式可以明显的提高 CPU 的利用率,但是也带了另外一种后果就是系统的线程切换增加。增加的 CPU 使用时间能不能补偿系统的切换成本需要好好评估。
3 序列化
Java的对象序列化将那些实现了Serializable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象。这一过程可通过网络进行,这样序列化机制能够自动弥补不同操作系统之间的差异。对应序列化的聪明之处在于它不仅保存了对象的“全景图”,而且能够追踪到对象自所包含的引用,并保存这些对象;接着又能够对对象内包含的每个这样的引用进行最终;以此类推。
要实例化一个对象,首先创建某些OutputStream对象,然后将其封装在一个ObjectOutputStream对象内,这是,只需要调用writeObject()即可将对象序列化,并将其发送到OutputStream(对象序列化基于字节,因此使用InputStream和OutputStream继承类层次结构)。反序列化和序列化过程正好相反,需要将一个InputStream封装在ObjectInputStream内,然后调用readObject()获取一个引用,它指向一个向上转型的Object,所以必须向下转型才能直接设置它们。下面是序列化和反序列化示例代码:
@Test
public void testWriteSerialization() {
try {
FileOutputStream fileOutputStream = new FileOutputStream("h:\\serialize.txt");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject("start");
objectOutputStream.writeObject(new Person("luoxn28", 23));
objectOutputStream.writeObject(12);
objectOutputStream.close(); } catch (IOException e) {
e.printStackTrace();
} System.out.println("end...");
} @Test
public void testReadSerialization() {
try {
FileInputStream fileInputStream = new FileInputStream("h:\\serialize.txt");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
String info1 = (String) objectInputStream.readObject();
Person person = (Person) objectInputStream.readObject();
int num = (int) objectInputStream.readObject(); System.out.println(info1);
System.out.println(person);
System.out.println(num); } catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
参考资料:
2、Java IO系统
Java IO工作机制分析的更多相关文章
- Java 类反射机制分析
Java 类反射机制分析 一.反射的概念及在Java中的类反射 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.在计算机科学领域,反射是一类应用,它们能够自描述和自控制.这类应用通过某 ...
- Java 动态代理机制分析及扩展
Java 动态代理机制分析及扩展,第 1 部分 王 忠平, 软件工程师, IBM 何 平, 软件工程师, IBM 简介: 本文通过分析 Java 动态代理的机制和特点,解读动态代理类的源代码,并且模拟 ...
- Java 动态代理机制分析及扩展,第 1 部分
Java 动态代理机制分析及扩展,第 1 部分 http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/ 本文通过分析 Java 动态代理的机制和特 ...
- 磁盘IO工作机制
磁盘IO工作机制 ref: <深入分析java web 技术内幕> by:许令波 几种访问文件的方式 文件读取和写入的 IO 操作都是调用操作系统提供的接口,因为磁盘设备是由操作系统管理的 ...
- [转]Java 动态代理机制分析及扩展
引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执 ...
- Java 动态代理机制分析及扩展--转
http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/#icomments http://www.ibm.com/developerworks/c ...
- 网络 IO 工作机制
ref: 深入分析 java web 技术内幕 2.3 两台计算机之间进行数据的传输需要经过很多步骤.首先有相互沟通的意向,然后还要有沟通的通道:通过电话还是面对面交流(物理链路).最后,两个人说话的 ...
- Java IO设计模式彻底分析 (转载)
一.引子(概括地介绍Java的IO) 无论是哪种编程语言,输入跟输出都是重要的一部分,Java也不例外,而且Java将输入/输出的功能和使用范畴做了很大的扩充.它采用了流的 机制来实现输入/输出,所谓 ...
- Java垃圾回收机制分析
Java的堆是一个运行时数据区,类的实例从中分配空间,堆中存储着正在运行的应用程序所建立的所有对象.垃圾回收是一种动态存储管理技术.它按照特定的垃圾回收算法,自动释放掉不再被引用的对象.堆内存里垃圾的 ...
随机推荐
- C#获得MAC地址(网卡序列号)代码
代码如下: //获得网卡序列号 //MAc地址 http://www.cnblogs.com/sosoft/ public string GetMoAddress() { string MoAddre ...
- customErrors与错误页面
本配置节相对简单而且常用 <customErrors defaultRedirect="url" mode="On|Off|RemoteOnly"> ...
- Asp.net 面向接口可扩展框架之数据处理模块及EntityFramework扩展和Dapper扩展(含干货)
接口数据处理模块是什么意思呢?实际上很简单,就是使用面向接口的思想和方式来做数据处理. 还提到EntityFramework和Dapper,EntityFramework和Dapper是.net环境下 ...
- 表达式括号匹配(stack)
题目描述 假设一个表达式由英文字母(小写).运算符(+.-.*./)和左右小(圆)括号构成,以“@”作为表达式的结束符.请编写一个程序检查表达式中的左右括号是否匹配,若匹配,则返回“YES”:否则返回 ...
- 引用js实现checkbox批量选中
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 从零开始学Python第七周:面向对象进阶(需修改)
一,类的属性 (1)示例 通过属性获取已经创建对象的个数 class Plane: pCount = 0 #类属性 def __init__(self,name,category): self.nam ...
- 转载:《TypeScript 中文入门教程》 7、模块
版权 文章转载自:https://github.com/zhongsp 建议您直接跳转到上面的网址查看最新版本. 关于术语的一点说明: 请务必注意一点,TypeScript 1.5里术语名已经发生了变 ...
- 【工匠大道】Git的使用总结
初衷是想将一些常用的代码整理在博客园上,但是考虑到博客园上的代码量多,需要折叠,折叠后就不能直接修改,于是想到了 大家都常用的 gitHub来进行代码的管理. 其实之前我是用过 Osa的git的,但是 ...
- jquery如何实现(textarea) placeholder自动换行?
思路:利用文本框的聚焦和失焦事件 1.HTML结构 <textarea id="text1"></textarea> 2.js方法 <script&g ...
- js中Unicode转义序列
将某一中文字符转义,可采取在线工具进行转义,http://tool.chinaz.com/tools/unicode.aspx "哈哈" ==="\u54c8\u54c8 ...