Java NIO:编写文件头 - 使用SeekableByteChannel

时间:2013-11-28 10:06:17

标签: java nio

我手动将数据对象序列化为文件,使用ByteBuffer及其操作,例如putInteger()putDouble()等。

我想写出的一个字段是String。例如,假设这包含一种货币。每种货币都有一个三字母的ISO货币代码,例如英镑为英镑。

假设我正在序列化的每个对象只有一个双倍和一个货币;您可以将序列化数据视为:

100.00|GBP
200.00|USD
300.00|EUR

显然,实际上我并没有界定数据(字段之间的管道,也不是换行符),它是以二进制形式存储的 - 只是使用上面的例子。

使用每个条目对货币进行编码效率有点低,因为我一直存储相同的三个字符。相反,我想要一个标题 - 它存储货币的映射。该文件看起来像:

100
GBP
USD
EUR
~~~
~~~
100.00|1
200.00|2
300.00|3

文件中的前2个字节是一个短的,用十进制值100填充。这告诉我文件中的货币有100个空格。在此之后,有3个字节的块是按顺序的货币(仅ASCII字符)。

当我重读文件时,我所要做的就是建立一个带有货币代码的100元素阵列,我可以便宜/有效地查找每一行的相关货币。

回读文件似乎很简单。但我很想听听关于写出数据的想法。

我不知道前面的所有货币,我实际上支持任何三字符代码 - 即使它是无效的。因此,我必须建立将货币转换为指数的表格。

我打算使用SeekableByteChannel来处理我的文件,并在每次找到我之前未编入索引的新货币时回头查询。

这对于移动文件有明显的I / O开销。但是,我期望在前几个数据对象中看到所有不同的货币。所以它可能只会寻找执行的前几秒,然后不必再进行额外的数小时搜索。

另一种方法是等待数据流完成,然后再写一次标题。但是,如果我的应用程序崩溃并且我没有写出标头,则文件中的数据无法恢复到原始内容。

寻求合适的事情似乎是正确的,但我之前没有尝试过 - 并且希望能够预先听到恐怖故事,而不是通过我的审判/错误。

1 个答案:

答案 0 :(得分:0)

您的方法存在的问题是您说您不想限制货币代码的数量,这意味着您不知道您需要为标题预留多少空间。如果不经常执行,在普通本地文件中查找可能会很便宜,但是移动整个文件内容以为标题保留更多空间

另一个问题是如何定义效率。如果不限制货币代码的数量,则必须注意单个字节不足以满足索引的情况,因此需要动态的可能多字节编码,这种编码更难以解析或修复多字节编码,最终采用与货币代码本身相同的字节数。

因此,如果不是典型情况下的空间效率比解码效率更重要,则可以使用这些代码全部仅由ASCII字符组成的事实。因此,您可以用三个字节对每个货币代码进行编码,如果接受一个填充字节,则可以使用单个putInt / getInt来存储/检索货币代码,而无需任何标头查找。

我不相信进一步优化这些代码会显着改善您的存储。该表格仅包含货币代码。其他数据很可能会占用更多空间。