I/O

java中的file对象实际上只是一个抽象的概念,FileDescriptor才是真正意义上指代file的对象。

输出流负责写入数据,输入流负责负责读取数据。
相比于输入输出流,缓冲流有一块区域叫做缓冲区,缓冲区用于数据流的缓存,如果向缓冲流中读取数据,首先是从缓冲区中读取数据,如果此时的缓冲区为空,系统会自动的从磁盘中读取数据,尽可
能的填充满缓冲区,此时从设备中读取的数据并不会直接发送给外部设备而是暂存于缓冲区中。
在处理输入流的时候一般都是一个一个字节的读取输入流内的数据,不过也可以通过一段缓冲区来指定读取的字节数:

byte[] buffer = new buffer[1024];
while(inputStream.read(buffer) != -1){
    outputStream.write(buffer);
}

可以把文件想象出一个用于装字节的容器,FileInputStream 想像成一个水管用于抽取文件中的字节s,对应的FileOutputStream就是一个专门用于向容器中注入字节s
哎,其实主要是根据命名去理解stream太蛋疼了,文件输出流不应该是用于抽取文件字节 文件输入流不应该是用于注入字节的吗?咋刚好相反呢 ?
或者把输入输出流以buffer作为基准,输入流需要把文件的内容输出到这一块buffer来,所以对应的是 read 方法,对应的输出流则是把buffer的内容输入到文件内所以对应的方法是write。
数据流有一块区域称之为缓冲区,上面说了缓冲区是干嘛的,每次输出数据的时候数据最先到达的是缓冲区而不是直接传到磁盘中去,只有当缓冲区满了或者调用了关闭流的函数才能把数据传输到
磁盘存储中,所以说调用close一方面是为了释放资源另一方面也是为了把最后一次输入到缓冲区的数据强制刷到磁盘中,否则的话无法保证数据的完整性。

利用缓冲机制来提升读取数据流的效率:
实际上每次调用read都会从OS请求分发一个字节,一般的做法就是一个while循环取出所有数据这样未免效率略低,所以可以采用缓冲机制,一次性从os请求一个数据块放在数据流的缓冲区,
每次读取字节跳过os直接从缓冲区读取字节这样减少与os的交互从而提升效率。而自带缓冲机制的则是BufferedInputStream, 所以需要把数据源包装一下从而获得可用缓冲区。

nio是基于数据块的普通io是基于数据流的,前者把最耗时的io操作(也就是把数据流填充到缓冲区或者将缓冲区的数据流提取出来)都转移给了操作系统去完成,以前都是基于一个一个字节来传数据
此时可以以一个缓冲区的容积(也就是所谓的数据块)作为基本单位来传输数据。
普通io操作数据流有个api是 read(byte[])/write(byte[]) 看起来像是一次消费了byte数组长的数据(可以看作数据块),然而实际上实现的方式是遍历这个字节数组,真正去消费数据流还是一个
write(int oneByte)/read(int oneByte),所以说面向流的io是很慢的。不过一个字节一个字节的传输有一个好处就是可以精准的过滤每一个字节,可以为一个数据流创建多个过滤器,例如如下代码:
new BufferedInputStream(new FileInputStream(“textByte.txt”))

序列化的问题
如果一个对象a持有了另外一个对象b的引用,那么此时如果想要序列化掉a,需要把对象b的引用地址序列化到对象a中去吗?
当然是不行的,即使把对象b的引用放入了对象a中那么再次加载对象a无法保证引用指向的地址依旧对应的是对象b,它的对应的引用地址可能已经被回收而新生成的对象b地址可能在其他的地方。
具体的做法就是为对象引用建立一个model并且赋予它一个序列号,比如说对象a饮用到了对象b,首先要做的就是把对象b的值存储起来,然后跟对象a建立起关系(也就是说对象a引用到了对象b,
也就是objB->modelBNum)这样的话在反序列化的时候就可以把对象a完整的取出来而对象b也能够重新实例化出来并且恢复序列化前跟对象a之间的联系。