2013-11-28 67 views
0

我手动序列化的数据对象到一个文件,使用字节缓冲区和它的操作,如putInteger()putDouble()的Java NIO:写入文件头 - 使用SeekableByteChannel

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

假设我序列化的每个对象只有一个double和一个货币;你可以考虑序列化的数据看起来是这样的:

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

您是否考虑过使用嵌入式数据库?否则,它会像我正在重新发明轮子一样,像交易数据库一样寻找我。 – Robert

+0

@Robert我正在存储的数据需要进行索引才能进行快速访问。鉴于我的数据是固定宽度,我可以非常快速地找到第n个元素,找到数据有效负载的开始,然后寻找n *对象大小的字节。我将存储数以百万计的记录,并且输入速率非常“突然” - 在每天的特定时间,我可以每秒收到数十万条记录。我正在寻找速度非常快的东西,我不一定需要具有类似SQL的嵌入式数据库的所有功能的东西。像Derby/HSQLDB这样的产品太慢了。 – jwa

+0

好的,如果你想自己编码一个优化版本使用两个文件,一个用于货币,一个用于数据,那么你不必考虑偏移量... – Robert

回答

0

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

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

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

我不认为进一步优化这些代码会显着提高存储容量。该表格不仅包含货币代码。其他数据很可能会占用更多的空间。

+0

我没有说我不知道想要限制货币代码的数量:-)我愿意先声明这个,可能在config中。在上面的例子中,我会为100种货币预留足够的空间。如果我试图放入第101种货币,我会抛出异常....因此,我绝对不想移动文件的内容,以便为更大的标题制作方式。 – jwa

+0

货币代码是例子,还有其他的例子,其中字符的数量将会更长,比如说10个。我正在考虑假设编码的索引号(1,2,3 ...)是短的而不是一个字节。这将为我的所有用例提供足够的索引。 – jwa

+0

我强调你的陈述'如果不太经常执行,在普通的本地文件中查找可能会很便宜。鉴于我愿意做出的限制(按照上述评论),听起来像您认为这是一个合理的方法? – jwa