Node.js v0.10:replace文件中的某些字节而不读取整个文件

我正在做一个文本编辑器和编辑一个文件,我真的需要某种方式来只读取文件中的某些字节,我已经使用fs.createReadStream取得了startend选项。

我也需要replace文件中的某些字节。 我不知道如何做到这一点。 到目前为止,我提出的最好的解决scheme是使用stream读取文件,然后写入一个新的文件,当我遇到的字节,我正在寻找我写我的新内容,而不是用旧的东西新的东西。

这不是最好的方式,你可能知道。 要编辑4个字节,我正在读取一个巨大的2GB文件,并写入2GB(假设我正在编辑一个2GB文件),效率不高。

达到这个目标的最好方法是什么? 我已经花了两个星期的时间做这个,我也想过使用缓冲区,但缓冲区将整个文件加载到内存中,如果是2GB的文件,那么这个效率再次不高。

你将如何实现replace文件中的某些字节而不读取整个文件,也不需要安装一些具有C ++代码的npm包。 我不希望我的编辑器必须编译C ++代码。

如果这样做不是直截了当的,如何删除文件中的某些字节而不读取整个文件? 如果我能做到这一点,那么我可以删除要replace的字节,并使用fs.write()类的东西来添加我希望它们被replace的字节。

编辑#1:

玩过之后,我发现如果我用r+ open打开一个带有标志r+打开文件,然后用fs.write replace一些东西。 所以如果文本是“Lorem ipsum”,我fs.write “!!!!” 结果将是“!!!! m ipsum”。

如果只有我要写的所有东西都是完美的长度,这将工作得很好。 :/

我知道在新内容不是完美的长度的情况下该怎么办,但我不知道如何。 :/也许如果有某种“空字节”…

编辑#2:

所以如上所述, fs.open (带有r+ flags选项)+ fs.write允许我覆盖文件中的内容,而不读取整个文件,这太棒了。 现在,我遇到了一个新问题。 我们来看下面的文件:

 one\n two\n three\n 

如果我fs.open在字节0,然后fs.write “是”,我结束了:

 yes\n two\n three\n 

如果我这样做,而不是fs.write “niet”,我最终:

 niettwo\n three\n 

请注意\n字符是如何replace为“t”的,这是因为在fs.open使用r+时, fs.write工作方式是replace字节。 这是我现在要解决的问题。

如何做一些像“从这个字节到这个字节,取代它与这些其他字节”,所以我的function可能是像function replaceBytes(filePath, newBytes, startByte, endByte) ,这将只会从startByteendByte ,无论newBytes有多长,是否比endByte - startByte的长度更短或更长。

编辑#3:

好的,我想出了新内容比被replace的旧内容更长的情况。 感谢\x00 ,我已经能够弄清楚了。 如果新旧内容的长度相同,则不难理解,因为这里没有任何内容。

但是旧内容比新内容短的情况下,仍然没有解决。

对于那些好奇的人来说,这是旧内容的工作代码比新内容长: https : //github.com/noedit/file/blob/592a35134440a03d3e3c3e366f6cda7f565c11aa/lib/replaceBytes.js#L27-L34

虽然它确实在那里放置一个空字节,这取决于编辑器,它可能会显示为一个字符,因此看起来很奇怪。 :/

正如你已经发现, fs.write r+模式允许你覆盖字节。 这对于添加和删除的片段长度完全相同的情况就足够了。

当添加的文本短于删除的文本时,我build议您不要使用\x00字节填充,如您在其中一个编辑中所build议的那样。 这些在大多数types的文件中是完全有效的字符(在源代码中,它们通常会导致编译器/解释器抛出错误)。

简而言之,这通常是不可能的。 这不是一个抽象问题; 在文件系统级别,文件以连续字节的块存储。 没有通用的方法来从文件的中间插入/删除。

正确的方法是find需要更改的第一个字节,然后写入文件的其余部分(除非您已经添加/删除了相同数量的字节,在这种情况下你可以停止写作)。

为了避免在长时间写入等情况下发生崩溃问题,通常要写入临时文件位置,然后用临时文件替代您希望保存的实际文件。

如果你用一个合适的文件模式(如r+ )手动打开一个文件( fs.open() ),则可以使用fs.write()在文件中的特定位置进行写入。

如果你需要更灵活的文件查找,那么在npm上有一些模块,例如fs-ext ,它提供了fs.seek() ,允许你从当前位置寻找一些n字节的偏移量。

尝试下面的代码片段:

新解决scheme:

 var fs = require('fs'); var startByte = 3, endByte = 6, newBytes ='replacing with this line', filePath ='sample.txt'; function replaceBytes(filePath, startByte, endByte, newBytes) { var fsWriteStream = fs.createWriteStream('temp.txt', {flags: 'w+'}); var fsReadStream = fs.createReadStream(filePath, {start: endByte+1}); fsReadStream.pipe(fsWriteStream); fsWriteStream.on('finish', function(){ var fsReadStream2 = fs.createReadStream('temp.txt'); var fsWriteStream2 = fs.createWriteStream(filePath, {start: startByte, flags: 'r+'}); fsWriteStream2.write(newBytes); fsReadStream2.pipe(fsWriteStream2); //fsWriteStream2.end(); }); } replaceBytes(filePath, startByte, endByte, newBytes); 

旧解决scheme:

s – 开始字节

R – 文本被replace

文件 – 文件必须被replace的文件

 var fs = require('fs'); var s = 3, R ='replacing with this line', file ='sample.txt'; function replace(file, s, R) { var N = R.length; var fsWriteStream = fs.createWriteStream(file, {start: s, flags: 'r+'}); fsWriteStream.write(R); fsWriteStream.end(); } replace(file, s, R);