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

时间:2015-06-10 22:48:17

标签: node.js file-io

我正在创建一个文本编辑器并且为了编辑文件我真的需要某种方式来只读取文件中的某些字节,我使用fs.createReadStream来完成start和{ {1}}选项。

我还需要替换文件中的某些字节。我不确定如何做到这一点。到目前为止,我提出的最佳解决方案是使用流读取文件,然后写入新文件,当我遇到我正在寻找的字节时,我会编写新内容,从而替换旧的内容新的东西。

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

实现这一目标的最佳方法是什么?我花了两周的时间做这个,我也想过使用Buffers,但Buffers将整个文件加载到内存中,如果它是2GB的文件,那么效率也会很高。

如果不读取整个文件并且没有安装一些具有C ++代码的npm软件包,您将如何实现替换文件中的某些字节。我不希望我的编辑器必须编译C ++代码。

如果这样做并不简单,那么如何在不读取整个文件的情况下从文件中删除某些字节呢?如果我可以这样做,那么我可以删除要替换的字节,并使用类似end的内容来添加我想要替换的字节。

编辑#1:

在玩完之后,我发现如果我打开的文件fs.write()带有标记fs.open,然后r+ 替换的内容。所以如果文字是“Lorem ipsum”而我fs.write“!!!!”结果将是“!!!! m ipsum”。

如果我要编写的所有东西都是完美的长度,这样就行了。 :/

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

编辑#2:

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

fs.write

如果我{0}位于字节0,然后one\n two\n three\n “是”,我最终得到:

fs.open

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

yes\n
two\n
three\n

注意fs.write字符是如何被替换为“t”的,这是因为niettwo\n three\n \n中使用fs.write时替换字节时的工作原理。这是我现在想解决的问题。

如何做一些事情,比如“从这个字节到这个字节,用其他字节替换它”,所以我的函数可能类似r+,只能从fs.open替换为function replaceBytes(filePath, newBytes, startByte, endByte) startByte,无论多长endByte,是否短于或长于newBytes

编辑#3:

好的,我想出了新内容比正在替换的旧内容更长的情况。感谢endByte - startByte,我已经弄明白了。如果新内容和旧内容的长度相同,那就不难理解,因为那里没什么可做的。

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

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

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

3 个答案:

答案 0 :(得分:7)

正如您所发现的,fs.write r+模式允许您覆盖字节。这足以满足添加和删除的部分长度完全相同的情况。

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

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

执行此操作的正确方法是寻找您需要更改的第一个字节,然后写入文件的其余部分(除非您达到添加/删除相同数量的文件的位置)字节,在这种情况下你可以停止写。)

为了避免在长时间写入期间崩溃等问题,通常会写入临时文件位置,然后mv临时文件代替您要保存的实际文件。

答案 1 :(得分:4)

Try below code snippet:

New Solution:

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);

Old Solution:

s - start byte

R - text to be replaced with

file - file where text has to be replaced

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);

答案 2 :(得分:2)

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

如果您需要更灵活的文件搜索,npm上有一些模块,例如fs-ext提供fs.seek(),允许您从当前搜索某些偏移 n 字节举个例子。