读取/写入java中的大型文件

时间:2011-04-01 11:13:09

标签: java file-io binaryfiles

我有一个格式如下的二进制文件:

[N bytes identifier & record length] [n1 bytes data] 
[N bytes identifier & record length] [n2 bytes data] 
[N bytes identifier & record length] [n3 bytes data]

如你所见,我有不同长度的记录。在每个记录中我有N个字节固定,其中包含和id以及记录中的数据长度

此文件非常大,可包含3百万条记录。

我想通过应用程序打开此文件,让用户浏览和编辑记录。 (插入/更新/删除记录)

我的初步计划是从原始文件创建和索引文件,并为每条记录保留下一个和上一个记录地址,以便轻松地前后导航。 (某种链表,但文件不在内存中)

  • 是否有库(java库)来帮助我实现这个要求?

  • 您认为有用的任何推荐或经验?

----------------- EDIT ----------------------------- -----------------

感谢您提供指南和建议,

更多信息:

原始文件及其格式不受我的控制(它是第三方文件),我无法更改文件格式。但我必须阅读它,让用户浏览记录并编辑其中一些(插入新记录/更新现有记录/删除记录),最后将其保存回原始文件格式

你仍然推荐使用DataBase 而不是普通的索引文件吗?

----------------- SECOND EDIT ---------------------------- ------------------

更新模式下的记录大小是固定的。它表示更新(编辑)的记录与原始记录的长度相同,除非用户删除记录并创建另一种格式不同的记录。

非常感谢

6 个答案:

答案 0 :(得分:2)

说真的,你不应该为此使用二进制文件。您应该使用数据库。

尝试将其作为常规文件实现的问题源于操作系统不允许您在现有文件的中间插入额外字节这一事实。因此,如果您需要插入记录(除了结尾之外的任何地方),更新记录(具有不同的大小)或删除记录,您需要:

  • 重写其他记录(在插入/更新/删除点之后)以制作或回收空间,或
  • 在文件中实现某种可用空间管理。

所有这些都很复杂和/或昂贵。

幸运的是,有一类软件可以实现这种功能。它被称为数据库软件。有多种选择,从使用全面的RDBMS到轻量级的解决方案,如BerkeleyDB文件。


在回复第1次和第2次编辑时,数据库仍然会更简单。

但是,这里有一个替代方案,可能为这个用例执行比使用数据库更好的 ...而不进行复杂的自由空间管理。

  1. 读取文件并构建一个 in-memory 索引,将ids映射到文件位置。

  2. 创建第二个文件以保存新的和更新的记录。

  3. 执行记录添加/更新/删除:

    1. 通过将新记录写入第二个文件的末尾并为其添加索引条目来处理添加。

    2. 通过将更新的记录写入第二个文件的末尾,并将现有的索引条目更改为指向它来处理更新。

    3. 通过删除记录密钥的索引条目来处理删除。

  4. 按如下方式压缩文件:

    1. 创建新文件。

    2. 按顺序读取旧文件中的每条记录,并检查记录键的索引。如果条目仍指向记录的位置,请将记录复制到新文件。否则跳过它。

    3. 对第二个文件重复步骤4.2。

  5. 如果我们成功完成上述所有操作,请删除旧文件和第二个文件。

  6. 请注意,这依赖于能够将索引保留在内存中。如果这不可行,那么实现将变得更加复杂......更像是数据库。

答案 1 :(得分:2)

拥有一个数据文件和一个索引文件将是这种实现的一般基础思想,但你几乎发现自己在重复数据更新/删除等时处理数据碎片。这类项目本身,应该是一个单独的项目,不应该是您的主要应用程序的一部分。但是,基本上,数据库是您需要的,因为它是专门为此类操作和用例设计的,并且还允许您搜索,排序和扩展(更改)您的数据结构,而无需重构内部(自定义)溶液

我建议你下载Apache Derby并创建一个本地嵌入式数据库(德比为你做,因为你希望你在运行时创建一个新的嵌入式连接)。它不仅会比您自己编写的任何内容更快,而且会使您的应用程序更易于维护。

Apache Derby是一个单独的jar文件,您只需在项目中包含和分发(如果您的应用中可能存在任何法律问题,请查看license)。不需要数据库服务器或第三方软件;它都是纯Java。

底线因为这一切都取决于您的应用程序有多大,如果您需要在多个客户端共享数据,速度是您的应用程序的关键方面等等。

对于独立的单用户项目,我推荐使用Apache Derby。对于n-tier应用,您可能希望查看MySQLPostgreSQL或( hrm )甚至Oracle。使用已经制造和测试的解决方案不仅智能,而且会缩短您的开发时间(和维护工作)。

干杯。

答案 2 :(得分:1)

通常,您最好让图书馆或数据库为您完成工作。

您可能不希望拥有SQL数据库,并且有许多简单的数据库不使用SQL。 http://nosql-database.org/列出了122个。

至少,如果您打算写这篇文章,我建议您阅读其中一个数据库的来源,了解它们的工作原理。


根据记录的大小,300万不是那么多,我建议你保留尽可能多的内存。

您可能遇到的问题是确保数据一致并在发生损坏时恢复数据。第二个问题是有效地处理碎片(有一些事情是处理GC处理的最聪明的人)第三个问题可能是使用源数据以事务方式维护索引,以确保没有不一致。

虽然这一开始可能看起来很简单,但确保数据可靠,可维护且可以高效访问存在很大的复杂性。这就是为什么大多数开发人员使用现有的数据库/数据存储库并专注于其应用程序无关的功能的原因。

答案 3 :(得分:0)

(注意:我的答案是关于一般的问题,不考虑任何Java库或 - 像其他答案也提出 - 使用数据库(库),这可能比重新发明轮子更好)

创建索引的想法很好,并且在性能方面非常有用(尽管你写了“索引文件”,我认为它应该保存在内存中)。如果您读取每个条目的ID和记录长度,然后只是通过文件搜索跳过数据,那么生成索引应该非常快。

您还应该考虑编辑功能。如果你做错了,那么在如此大的文件上插入和删除会非常慢(例如,删除然后移动所有以下条目以缩小差距)。

最佳选择是仅将已删除的条目标记为已删除。插入时,您可以覆盖其中一个或附加到文件的末尾。

答案 4 :(得分:0)

  

插入/更新/删除记录

插入(而不是仅仅附加)和删除文件到文件是很昂贵的,因为您必须移动文件的所有以下内容,以便为新记录创建空间或删除它使用的空间。如果更新改变了记录的长度(你说它们是可变长度),更新同样很昂贵。

您建议的文件格式基本上不适合您要执行的各种操作。其他人建议使用数据库。如果您不想走那么远,那么添加索引文件(如您所建议的那样)就是您的选择。我建议使索引记录的长度相同。

答案 5 :(得分:0)

正如其他人所说,数据库似乎是更好的解决方案。以下是可以使用的Java SQL DB:H2DerbyHSQLDB

如果您想使用索引文件,请查看Berkley DBNo Sql

如果有使用文件的原因,请查看JRecord。它有

  1. 几个用于读/写具有可变长度二进制记录的文件的类(它们是为Cobol VB文件编写的)。任何Mainframe / Fujitsu / Open Cobol VB文件结构都可以完成这项工作。
  2. 编辑 JRecord 文件的编辑器。最新版本的编辑器可以处理大文件(它使用压缩/溢出文件)。编辑器不得不下载整个文件,只有一个用户可以一次编辑该文件。
  3. JRecord解决方案仅在

    时有效
    • 有限数量(最好是一个)用户都位于一个位置
    • 快速信息结构