【问题标题】:Is there a better way to overwrite file contents?有没有更好的方法来覆盖文件内容?
【发布时间】:2012-06-30 12:23:27
【问题描述】:

我希望覆盖已经存在的文件的内容。显然,我可以根据this answer 创建一个覆盖旧文件的新文件。但是,我正在编写一个可能会多次执行此操作的程序,并且我想尽可能减少不必要的开销。

所以我的问题是:有没有更好的方法来简单地重写文件本身的内容,而不是编写一个替换旧文件的“新”文件?还是简单地覆盖整个文件内容的开销大致相当于创建新文件然后写入它的开销? (为了记录,这些文件只有 1 KB 大。)

【问题讨论】:

  • 您确实了解文件是如何存储在磁盘上的,以及这如何限制了它们的处理方式,对吗?
  • 我不确定我是否明白你在问什么。我有一定程度的了解,但我不会说我是磁盘数据存储方面的专家。我在二年级和三年级之间是一名计算机科学专业的学生(不过这不是家庭作业),所以我们已经介绍了一些文件存储,但在我的课程中并没有太多。
  • Redis这样的数据库或键值存储代替文件怎么样?
  • @cpeisert 不幸的是,我能做的有点有限——我的程序调用了另一个程序,该程序将某种格式的文件作为输入。所以我需要编写一组文件,在每个文件上调用第二个程序,获取结果,更改文件内容,然后再做一次;它是遗传算法的一部分。但是,我根本无法更改其他程序,所以我基本上必须将其视为黑匣子。
  • @Donal:当您有几百万个时,担心可能是有道理的……还记得在优化文件系统和 NNTP 服务器的挂载选项方面付出了多少努力吗? :)

标签: java file-io


【解决方案1】:

您可以使用RandomAccessFile 这是一个简短的示例:

         // create a new RandomAccessFile with filename test
     RandomAccessFile raf = new RandomAccessFile("c:/test.txt", "rw");

     // write something in the file
     raf.writeUTF("Hello World");

     // set the file pointer at 0 position
     raf.seek(0);

     // print the string
     System.out.println("" + raf.readUTF());

     // print current length
     System.out.println("" + raf.length());

     // set the file length to 30
     raf.setLength(30);

     // print the new length
     System.out.println("" + raf.length());

【讨论】:

  • 但仅当您以随机访问方式访问数据,并且仅当您将精确长度的数据替换为完全相同长度的数据时。
  • @ialiashhkevich 太棒了,这正是我正在寻找的替代方案。这些文件的长度总是大致相同(它们基本上只是以某种模式在其中包含数字的行),所以这似乎可以工作。但是现在,最初的问题是:什么开销更少 - 你的方法,还是我在原始帖子中链接到的答案的方法?
  • 如果只重写文件的一部分,那么 RandomAccessFile 的开销会更少。重写整个文件将与原始帖子的答案相同。
    由于您的程序调用另一个程序,该程序以某种格式的文件作为输入,因此您不必担心文件写入开销,调用另一个程序将占用您系统的大部分资源。
    我建议在多个线程中同时编写文件和调用程序,这样你可以从硬件中获得最大的性能。
【解决方案2】:

简短的回答:同时编写和配置文件。

较长的答案,需要大量挥手:

覆盖文件将涉及以下系统调用:

open
write
close

创建新文件、删除旧文件、重命名新文件将涉及以下系统调用:

open
write
close
unlink
rename

系统调用通常是程序中最慢的部分;一般来说,减少系统调用是加快程序速度的好方法。覆盖一个文件将重新使用操作系统的内部目录条目数据;这可能也会导致一些速度提高。 (它们可能很难用具有 VM 开销的语言来衡量......)

假设您在一次写入中更新整个 1K,您的文件足够小,应该以原子方式处理每个 write()。 (由于您关心性能,这似乎是一个安全的假设。)这确实意味着其他进程不应该看到 部分 写入,除非在灾难性电源故障和有损挂载选项的情况下。 (不常见。)即使在多次写入的情况下,文件重命名方法也能提供一致的文件。

但是,1K 文件是一种非常低效的存储机制;许多文件系统将沿 4k 块写入文件。如果这些数据块仅存在于您的应用程序中,那么将它们写入某种容器 中可能是有意义的,一次几个。 (Quake 派生系统这样做是为了从 zip 文件中读取它们的地图、纹理等,因为巨大的流式 IO 请求比数千个较小的 IO 请求快得多。)当然,如果您的应用程序正在编写,这会更难这些文件供其他应用程序使用,但如果这些文件很少共享,可能仍然值得研究。

【讨论】:

    【解决方案3】:

    只需将其用作链接答案中的示例。让操作系统/文件系统担心取消链接/链接 inode、磁盘上的位置等。如今,对于绝大多数软件开发而言,几乎没有充分的理由担心它。

    一般来说,CPU/磁盘 i/o 不会超过太多开销。如果您担心磁盘 i/o,请使用内存文件系统(前提是您不需要在发生崩溃时保留文件)或 SATA3 上的速度非常快的 SSD。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-20
      • 1970-01-01
      • 2017-07-13
      相关资源
      最近更新 更多