java对io提供的同步机制是什么意思_Java IO工作机制分析

本文介绍了Java IO的基本结构,包括基于字节和字符操作的接口,以及磁盘和网络操作接口。讨论了字节与字符之间的转换,并通过示例展示了FileReader、FileWriter、InputStreamReader和OutputStreamWriter的使用。同时,解释了同步与异步、阻塞与非阻塞的概念,以及Java对象序列化的原理和应用。
摘要由CSDN通过智能技术生成

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的类结构图如下所示:

67eda2204047a66906b2d37630bd0692.png

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

1a2dd3eb071d590ddedb4e381d795e81.png

关于各个子类的使用可以参考JDK 的 API 说明文档,这里我们需要注意的是:操作数据的方式是可以组合的,如下所示:

InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("h:\\haha.txt"), "utf-8");

从上面代码可以看出,InputStreamReader可以从FileInputStream中读取数据,从源码中可以看出来,其实不仅是InputStreamReader,所有的IO类都可以以这种方式来组合使用。

db0ac4d810ec851dacf84fed56b6fd8b.png

还有一点需要注意的是必须制定流最终写入到什么地方,是磁盘还是网络,从OutputStream类图中可以看出,写入网络中实际也是写文件操作,只不过底层是通过网络传输了。

1.2 基于字符的IO操作接口

不管是磁盘还是网络数据传输,都是以字节为单位的,但是程序中一般常见的数据操作都是以字符为单位的(Java中char占用2字节,C/C++中 char占用1字节),这就需要我们有一个操作字符的IO接口,来处理字符与字节见的编码转换问题,也就是Write和Reader接口及其实现类,他们 二者的类接口图如下:

cca698a9cad52753c8dbd7f141e5a329.png

aee7fed3472a145eeac9bd3461923c64.png

读字符接口Reader的最主要操作方法为read(),其读取字符并返回读取的字符数,不管是 Writer 还是 Reader 类它们都只定义了读取或写入的数据字符的方式,也就是怎么写或读,但是并没有规定数据要写到哪去(比如磁盘或者网络)。

1.3 字节与字符的转化接口

有时数据持久化和网络传输是以字节进行的,所有需要字节和字符之间的相互转换。

9cf17b3f97aab85ff1bf56a65328a93b.png 

00620c369719e769db5c73ae9ed8177c.png

/*** 使用FileReader进行读取文件*/@Testpublic void testFileReader() throwsIOException {

FileReader fileReader= new FileReader("h:\\haha.txt");char[] buff = new char[512];

StringBuffer stringBuffer= newStringBuffer();while (fileReader.read(buff) > 0) {

stringBuffer.append(buff);

}

fileReader.close();

System.out.print(stringBuffer.toString());

}/*** 使用FileReader进行读取文件,然后FileWriter写入另一个文件*/@Testpublic void testFileReaderAndFileWriter() throwsIOException {

FileReader fileReader= new FileReader("h:\\haha.txt");char[] buff = new char[512];

StringBuffer stringBuffer= newStringBuffer();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进行读取文件*/@Testpublic void testInputStreamReader() throwsIOException {

InputStreamReader inputStreamReader= new InputStreamReader(new FileInputStream("h:\\haha.txt"), "utf-8");char[] buff = new char[512];

StringBuffer stringBuffer= newStringBuffer();while (inputStreamReader.read(buff) > 0) {

stringBuffer.append(buff);

}

System.out.println(stringBuffer.toString());

}

@Testpublic void testIntputStream2() throwsIOException {

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写入另一个文件*/@Testpublic void testOutputStreamWriter() throwsIOException {

InputStreamReader inputStreamReader= new InputStreamReader(new FileInputStream("h:\\haha.txt"), "utf-8");char[] buff = new char[512];

StringBuffer stringBuffer= newStringBuffer();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,所以必须向下转型才能直接设置它们。下面是序列化和反序列化示例代码:

@Testpublic voidtestWriteSerialization() {try{

FileOutputStream fileOutputStream = new FileOutputStream("h:\\serialize.txt");

ObjectOutputStream objectOutputStream= newObjectOutputStream(fileOutputStream);

objectOutputStream.writeObject("start");

objectOutputStream.writeObject(new Person("luoxn28", 23));

objectOutputStream.writeObject(12);

objectOutputStream.close();

}catch(IOException e) {

e.printStackTrace();

}

System.out.println("end...");

}

@Testpublic voidtestReadSerialization() {try{

FileInputStream fileInputStream= new FileInputStream("h:\\serialize.txt");

ObjectInputStream objectInputStream= newObjectInputStream(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系统

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值