我正在制作一个文本编辑器,为了编辑一个文件,我真的需要某种方法来只从文件中读取某些字节,这是我使用 fs.createReadStream
实现的。使用 start
和 end
选项。
我还需要替换文件中的某些字节。我不确定如何做到这一点。到目前为止,我提出的最佳解决方案是使用流读取文件,然后写入新文件,当我遇到要查找的字节时,我改为写入新内容,从而将旧内容替换为新东西。
这不是最好的方法,您可能知道。要编辑 4 个字节,我正在读取一个巨大的 2GB 文件并写入 2GB(假设我正在编辑一个 2GB 文件),至少效率不高。
实现这一目标的最佳方法是什么?我花了两周时间这样做,我也想过使用 Buffers,但是 Buffers 将整个文件加载到内存中,如果它是 2GB 的文件,这又是低效的。
如何在不读取整个文件且不安装一些具有 C++ 代码的 npm 包的情况下替换文件中的某些字节。我不希望我的编辑器必须编译 C++ 代码。
如果这样做并不简单,那么在不读取整个文件的情况下从文件中删除某些字节怎么样?如果我可以这样做,那么我可以删除要替换的字节并使用类似 fs.write()
的内容。添加我希望它们被替换的那些。
编辑 #1:
玩了之后,我发现如果我用 fs.open
打开一个文件带旗r+
然后 fs.write
那取代了东西。所以如果文本是“Lorem ipsum”而我 fs.write
“!!!!”结果将是“!!!!!!m ipsum”。
如果只有我要写的所有东西都是完美的长度,这会很好用。 :/
我知道在新内容不是完美长度的情况下该怎么做,但我不知道该怎么做。 :/也许如果有某种“空字节”......
编辑 #2:
如上所述,fs.open
(带有 r+
标志选项)+ fs.write
允许我在不读取整个文件的情况下覆盖文件中的内容,这太棒了。现在有了这个,我遇到了一个新问题。让我们获取以下文件:
one\n
two\n
three\n
如果我
fs.open
在字节 0 然后 fs.write
"is",我最终得到:yes\n
two\n
three\n
如果我做同样的事情而不是
fs.write
“niet”,我最终得到:niettwo\n
three\n
注意
\n
字符被替换为“t”,这是因为 fs.write
使用 r+
时通过替换字节来工作在 fs.open
.这是我现在正在努力解决的问题。人们将如何做诸如“从这个字节到这个字节,用这些其他字节替换它”之类的事情,所以我的函数可能类似于
function replaceBytes(filePath, newBytes, startByte, endByte)
这将仅替换来自 startByte
至 endByte
,不管多久newBytes
,无论是比endByte - startByte
的长度短还是长.编辑 #3:
好的,我想出了新内容比被替换的旧内容长的情况。感谢
\x00
,我已经能够弄清楚了。如果新旧内容的长度相同,这不难弄清楚,因为那里没有什么可做的。但是旧内容比新内容短的情况,仍然没有解决。
对于那些好奇的人,这是旧内容比新内容长的工作代码:https://github.com/noedit/file/blob/592a35134440a03d3e3c3e366f6cda7f565c11aa/lib/replaceBytes.js#L27-L34
尽管它确实在其中放置了一个空字节,这取决于编辑器,但它可能会显示为一个字符,因此看起来很奇怪。 :/
最佳答案
正如您所发现的,fs.write
与 r+
模式允许您覆盖字节。这对于添加和删除的片段长度完全相同的情况就足够了。
添加的文本比删除的文本短时,建议不要填写\x00
字节,正如您在其中一项编辑中所建议的那样。这些在大多数类型的文件中都是完全有效的字符(在源代码中,它们通常会导致编译器/解释器抛出错误)。
简短的回答是,这通常是不可能的。这不是抽象问题;在文件系统级别,文件存储在连续字节的块中。没有从文件中间插入/删除的通用方法。
执行此操作的正确方法是查找您需要更改的第一个字节,然后写入文件的其余部分(除非您达到添加/删除相同字节数的点,在这种情况下你可以停止写作)。
为了避免在长时间写入或类似情况下崩溃的问题,通常先写入临时文件位置,然后 mv
临时文件代替您要保存的实际文件。
关于Node.js v0.10 : Replace certain bytes in file without reading whole file,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30768630/