写在前面
最近研究一下JAVA中的顺序IO,在网络上找了一会儿,发现少有详细的介绍,顾此在此处说说顺序IO,才学疏浅,如有不对,望赐教。
什么是顺序IO
事实上JAVA具有很多操作文件的方案(方法), 许多程序需要将一些事件记录到本地存储中,常见的如数据库,MQ等,首先文件是许多带数据的块组成的,传统IO操作文件具有一个寻址过程(事实上硬件上也会存在寻道,旋转延迟等因素),小文件尚可,大文件就比较消耗性能和时间,比如数据库分配的文件(本地),顺序IO具备指定位置的功能,但是任然需要我们维护一个偏移量(游标).
MappedByteBuffer
JAVA顺序IO通过MappedByteBuffer实现,与传统IO不同的是,MappedByteBuffer需要使用者提供一个位置(偏移量),详细看以下代码:
mappedByteBuffer.position(index); mappedByteBuffer.put(content.getBytes(StandardCharsets.UTF_8));
代码中可见,通过MappedByteBuffer提供的api position();来指定位置(偏移量),put()进行写操作,详细如下。
写操作
先看代码:
public int write(File file ,String content ,int index,long size){ RandomAccessFile randomAccessFile; MappedByteBuffer mappedByteBuffer; try { randomAccessFile = new RandomAccessFile(file,"rw"); //1 FileChannel fileChannel = randomAccessFile.getChannel(); //2 mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE,0,size); //3 mappedByteBuffer.position(index); //4 mappedByteBuffer.put(content.getBytes(StandardCharsets.UTF_8)); //5 return mappedByteBuffer.position(); //6 }catch (Exception e){ e.printStackTrace(); } return 0; }
"r"仅供阅读。调用结果对象的任何写方法都会引发IOException。(Open for reading only. Invoking any of the write methods of the resulting object will cause an IOException to be thrown. )
"rw"开放阅读和写作。如果该文件不存在,那么将尝试创建它。(Open for reading and writing. If the file does not already exist then an attempt will be made to create it. )
“rws”和“rw”一样,对文件内容或元数据的每次更新都要同步写入底层存储设备。(Open for reading and writing, as with "rw", and also require that every update to the file's content or metadata be written synchronously to the underlying storage device. )
“rwd”和“rw”一样,都是打开的,可以读写,并且还要求对文件内容的每次更新都要同步写入底层存储设备。(Open for reading and writing, as with "rw", and also require that every update to the file's content be written synchronously to the underlying storage device. )
FileInputStream fileInputStream = new FileInputStream(file); FileChannel fileChannel = fileInputStream.getChannel();
运行结果,标记3处抛出异常:NonWritableChannelException
或者:
FileOutputStream fileInputStream = new FileOutputStream(file); FileChannel fileChannel = fileInputStream.getChannel();
运行结果,标记3处抛出异常:NonReadableChannelException
从上可以看到,不管是FileInputStream还是FileOutputStream获取到的IO通道,均有局限性,不适用MappedByteBuffer。
只读:任何修改结果缓冲区的尝试都将导致抛出ReadOnlyBufferException。(MapMode.READ_ONLY) (Read-only: Any attempt to modify the resulting buffer will cause a ReadOnlyBufferException to be thrown. (MapMode.READ_ONLY) )
读/写:对产生的缓冲区所做的更改最终将传播到文件;它们可能对映射了相同文件的其他程序可见,也可能不可见。(MapMode.READ_WRITE) (Read/write: Changes made to the resulting buffer will eventually be propagated to the file; they may or may not be made visible to other programs that have mapped the same file. (MapMode.READ_WRITE) )
Private:对产生的缓冲区所做的更改不会传播到该文件中,并且不会对映射了该文件的其他程序可见;相反,它们将导致创建缓冲区修改部分的私有副本。(MapMode.PRIVATE) (Private: Changes made to the resulting buffer will not be propagated to the file and will not be visible to other programs that have mapped the same file; instead, they will cause private copies of the modified portions of the buffer to be created. (MapMode.PRIVATE) )
参数二代表从指定位置开始映射,0表示从头开始映射全部内容,参数三表示要映射的区域大小,可超出文件大小(如字符长度为3,此处可填写6或者其他),但不可为负数或超出Integer.MAX_VALUE.
实际上到此处,IO通道已经完成了它的任务,可关闭。(在标记3之后任意位置可执行fileChannel.close()而不影响运行结果)
此处简要说明了个参数的意思,要加深了解建议自己建立Demo并更改此处参数观察运行结果。
上述代码中标记4位置中,通过MappedByteBuffer对象的position(); API设置写入位置,官方解释如下:
Sets this buffer's limit. If the position is larger than the new limit then it is set to the new limit. If the mark is defined and larger than the new limit then it is discarded.
上述代码中标记5位置中,将内容传输到缓冲区,可理解为写入,因为缓冲区的变动会传播到实际文件中,除了PRIVATE。
上述代码中标记6位置中,返回下一次操作时的位置。
此篇文章简要说明了一下JAVA顺序IO,有些地方没有详细说明,会持续维护更新此篇文章,感谢大家。