【问题标题】:Use java to modify file contents in place使用java就地修改文件内容
【发布时间】:2012-10-26 20:37:29
【问题描述】:

我需要就地修改文件的特定内容。
我确实想创建一个新文件并重写旧文件。而且文件很小,每个最大只有几 MB。
对于那些想知道的人(尽管我不确定这是否与 OP 有关),我需要修改属于版本控制的文件并且需要修改只读版本。就地进行修改要简单得多。
Java api可以做到这一点吗?
如果没有,是否有提供此功能的库?

【问题讨论】:

  • 为什么不想创建一个新文件来替换旧文件?这在出现故障时更加健壮,因为如果原始文件在中间失败,您还没有部分覆盖原始文件。
  • 您在寻找什么级别的 API?您可以使用原始字节,还是希望能够将其作为文本进行操作、插入/删除/修改字符串等?
  • 您最好从旧文件写入新文件,删除旧文件,然后重命名新文件。如果您尝试在文件中间添加更多信息,则会损坏文件内容。更好的是删除 .old 文件并使用 .old 扩展名重命名旧文件。这样,如果您的 I/O 中断,您不会丢失文件。
  • " 我需要修改属于版本控制的文件,需要修改只读版本" -- 只读意味着无法写入文件(或删除),无论您是否在原地执行此操作。

标签: java file-io inputstream nio


【解决方案1】:

Java 允许随机访问和写入磁盘上的文件。但是,写入文件中间只能覆盖字节——即用其他字节替换特定字节——并且不能插入数据到文件中间。为此,您必须在插入点之后重写所有内容。将文件视为恰好位于磁盘上的字符数组 (char[])。随机访问允许你做相当于

char[] file    = ... // the file on disk
char[] newData = ... // the data to be written
int pos = ...        // the position in the file to write to
for (i=0; i<newData.; i++) 
{ 
    file[pos+i] = newData[i];
}

插入文件中的数据需要与将数据插入数组相同的过程。插入点之后的所有数据都必须向右移动以容纳插入的数据。如果您要替换为 更短的 字符串(即删除字节),那么编辑后的数据必须向左移动。

其次,你说:

我需要修改属于版本控制的文件,并且需要修改只读版本

只读就是这个意思。如果文件是只读的,则无论是否使用随机访问,都不能以任何方式对其进行修改。

你也在评论中说:

新文件将不受源代码控制。我必须找到一种方法来添加它。我正在努力避免这种情况

如果文件受源代码控制,您很可能正在处理本地副本。只要更新的文件与原始文件具有相同的名称并且位于同一目录中,那么创建文件的新实例应该没有区别。您只需将更新的版本提交到源代码控制系统。

但是,如果您正在更新源代码控制系统存储库中的文件,那么您可能会永久损坏系统。

【讨论】:

  • 在我的情况下,我实际上必须替换 less bytes 比现有的。例如:ABCDEFGHIJKLMNOABC。这不行吗?
  • 你是对的。工作副本将是本地的。但我不确定我是否使用相同的名称不会有任何区别。我的意思是我必须删除文件然后创建一个具有相同名称的新版本。删除文件后,为什么即使名称相同,新文件也会被视为处于源代码管理之下?
  • 没有。看看我上面的编辑。如果用更少的字节替换,则必须将后面的数据左移(并缩短文件)。但这一切都不重要。如果您正在处理本地副本,只需创建一个新文件并重新提交。如果您试图在源代码控制系统不知情的情况下直接更改源代码控制存储库文件,则您只能靠自己,并且可能会造成重大损害。源存储库文件不应被源代码控制软件触及。
  • 源代码控制系统只关心文件名和数据内容,而不关心文件在磁盘上的物理位置。如果您在本地删除工作副本中的文件,然后使用相同的内容重新创建它,不通知源代码控制系统,源系统应将其视为未修改。
  • 1)如果我只是将空格字符添加到所有无关的数据中而不向左移动任何内容怎么办?2)当我手动更改文件时有什么区别?系统只知道它已签出.**我**正在修改它。不是系统
【解决方案2】:

假设您希望能够将文件内容作为文本进行操作,并假设文件适合内存(您说这是一个有效的假设),那么您可能会发现 Commons IO FileUtils 中的方法很有用:

http://commons.apache.org/io/apidocs/org/apache/commons/io/FileUtils.html

例如:

File f = new File("my-file.txt");
List<String> lines = FileUtils.readLines(f, "UTF-8");
List<String> outLines = modify(lines); // Do some line-by-line text processing
FileUtils.writeLines(f, "UTF-8", outLines);

因此,您将文件内容读入内存,在内存中对其进行修改,然后用内存中的新内容覆盖原始文件。这是否符合您的“就地”标准?

【讨论】:

  • 就地意味着不创建新文件并覆盖旧文件。
【解决方案3】:

Java 支持随机文件访问,尤其是使用seek()

看看:http://docs.oracle.com/javase/tutorial/essential/io/rafs.html

【讨论】:

  • 随机访问文件允许对文件内容进行非顺序或随机访问。要随机访问文件,您需要打开文件,寻找特定位置,然后读取或写入该文件。
猜你喜欢
  • 2012-11-24
  • 1970-01-01
  • 1970-01-01
  • 2010-12-09
  • 2014-12-11
  • 2012-01-23
  • 2021-07-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多