Node.js v0.10: Replace certain bytes in file without reading whole file
NickName:greduan Ask DateTime:2015-06-11T06:48:16

Node.js v0.10: Replace certain bytes in file without reading whole file

I am making a text editor and for editing a file I really need some sort of way to only read certain bytes from a file, which I've achieved using fs.createReadStream uisng the start and end options.

I also need to replace certain bytes in the file. I am not sure how this can be done. So far the best solution I've come up is to read the file using a stream and then write to a new file, when I come across the bytes I'm looking for I write my new content instead, thus replacing the old stuff with the new stuff.

This is not the best way, as you'll probably know. To edit 4 bytes I am reading a huge 2GB file and writing the 2GB (assuming I'm editing a 2GB file), not efficient in the least.

What is the best way to achieve this? I've spent two weeks doing this and I've also thought of using Buffers, but Buffers load the entire file into memory, which again is unefficient if it's a 2GB file.

How would you achieve replacing certain bytes in a file without reading the entire file and without installing some npm package that has C++ code. I don't want my editor to have to compile C++ code.

If doing that is not straightforward, how about deleting certain bytes from a file without reading the entire file? If I can do that then I can delete the bytes to be replaced and use something like fs.write() to add the ones I want them to be replaced with.

Edit #1:

After playing around, I've found that if I open a file with fs.open with flag r+ and then fs.write that replaces stuff. So if the text is "Lorem ipsum" and I fs.write "!!!!" the result will be "!!!!m ipsum".

This would work fine if only all the stuff I was going to write was the perfect length. :/

I know what to do in the case that the new content isn't the perfect length, but I don't know how. :/ Maybe if there was some sort of "empty byte"...

Edit #2:

So as said above, fs.open (with r+ flags option) + fs.write allow me to overwrite the content in a file without reading the entire file, which is terrific. Now with this I am running into a new problem. Let's take the following file:

one\n
two\n
three\n

If I fs.open at byte 0 and then fs.write "yes", I end up with:

yes\n
two\n
three\n

If I do the same but instead fs.write "niet", I end up with:

niettwo\n
three\n

Notice how the \n character was replaced with the "t", this is because of how fs.write works by replacing bytes when using r+ in fs.open. This is the problem I am trying to solve right now.

How would one go about doing something like "from this byte to this byte, replace it with these other bytes" so my function could be something like function replaceBytes(filePath, newBytes, startByte, endByte) and that would replace only from startByte to endByte, no matter how long newBytes, whether it be shorter or longer than the length of endByte - startByte.

Edit #3:

OK, I figured out the case where the new content is longer than the old content that is being replaced. Thanks to \x00, I've been able to figure it out. In case both the new and the old content are the same length, that's not hard to figure out as there's nothing to do there.

But the case where the old content is shorter than the new content, that's still unresolved.

For those curious, this is the working code for old content longer than new content: https://github.com/noedit/file/blob/592a35134440a03d3e3c3e366f6cda7f565c11aa/lib/replaceBytes.js#L27-L34

Although it does put a null byte in there, which depending on the editor, it may show up as a character and thus looking weird. :/

Copyright Notice:Content Author:「greduan」,Reproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/30768630/node-js-v0-10-replace-certain-bytes-in-file-without-reading-whole-file

Answers
Aaron Dufour 2015-06-16T16:40:59

As you've discovered, fs.write with r+ mode allows you to overwrite bytes. This suffices for the case where the added and deleted pieces are exactly the same length.\n\nWhen the added text is shorter than the deleted text, I advise that you not fill in with \\x00 bytes, as you suggest in one of your edits. Those are perfectly valid characters in most types of files (in source code, they will usually cause the compiler/interpreter to throw an error).\n\nThe short answer is that this is not generally possible. This is not an abstraction issue; at the file system level, files are stored in chunks of contiguous bytes. There is no generic way to insert/remove from the middle of a file.\n\nThe correct way to do this is to seek to the first byte you need to change, and then write the rest of the file (unless you get to a point at which you've added/deleted the same number of bytes, in which case you can stop writing).\n\nIn order to avoid issues with crashing during a long write or something like that, it is common to write to a temporary file location and then mv the temporary file in place of the actual file you wish to save.",


saquib khan 2015-06-15T15:05:09

Try below code snippet:\n\nNew Solution:\n\nvar fs = require('fs');\nvar startByte = 3,\n endByte = 6,\n newBytes ='replacing with this line',\n filePath ='sample.txt';\n\nfunction replaceBytes(filePath, startByte, endByte, newBytes)\n{\n\n var fsWriteStream = fs.createWriteStream('temp.txt', {flags: 'w+'});\n var fsReadStream = fs.createReadStream(filePath, {start: endByte+1});\n fsReadStream.pipe(fsWriteStream);\n\n fsWriteStream.on('finish', function(){\n var fsReadStream2 = fs.createReadStream('temp.txt');\n var fsWriteStream2 = fs.createWriteStream(filePath, {start: startByte, flags: 'r+'});\n fsWriteStream2.write(newBytes);\n fsReadStream2.pipe(fsWriteStream2);\n //fsWriteStream2.end(); \n });\n\n\n}\n\nreplaceBytes(filePath, startByte, endByte, newBytes);\n\n\nOld Solution:\n\ns - start byte\n\nR - text to be replaced with\n\nfile - file where text has to be replaced\n\nvar fs = require('fs');\nvar s = 3,\n R ='replacing with this line',\n file ='sample.txt';\n\nfunction replace(file, s, R)\n{\n var N = R.length;\n var fsWriteStream = fs.createWriteStream(file, {start: s, flags: 'r+'});\n fsWriteStream.write(R);\n fsWriteStream.end(); \n}\n\nreplace(file, s, R);\n",


More about “Node.js v0.10: Replace certain bytes in file without reading whole file” related questions

Node.js v0.10: Replace certain bytes in file without reading whole file

I am making a text editor and for editing a file I really need some sort of way to only read certain bytes from a file, which I've achieved using fs.createReadStream uisng the start and end options...

Show Detail

checking a file from a certain offset without reading the entire file

what I want to do is open a file(which is huge) and read from a certain point of bytes to an offset. in c# this can be done with: File.ReadAllBytes(file).Skip(50).Take(10).ToArray(); the proble...

Show Detail

In Node.js how do I change (overwrite) a byte in a binary file without adding bytes

In Node.js how do I change (overwrite) a byte in a binary file (at a certain offset) without adding bytes in between and changing its length? In C I would just do something like fopen() the file w...

Show Detail

Replacing a pattern in file without reading the whole file- Perl

I want to replace a pattern 'good' with 'bad' in my file. Currently what I am doing is: #!/perl/bin/perl $filename= "abc.txt"; open my $fh, $filename; my $text = do { local( $/ ); <$fh&am

Show Detail

Replace bytes in a file at specific index with specific length

In my app, I receive some files. At the beginning I just have the size of this file. So I create an empty file (filled of 0). After creating this file, I will receive 1024 bytes per seconds. Thoses...

Show Detail

Node.js delete first N bytes from a file

How to delete (remove | trim) N bytes from the beginning of a binary file without loading it in the memory? We have fs.ftruncate(fd, len, callback), which cuts out bytes from the end of the file (i...

Show Detail

Removing the first bytes in a file

Is there a way to remove the first few bytes of a file (truncating it from the front) without using programs like tail or without having to read the whole contents of the file? That is because th...

Show Detail

Read info of pdf file without reading whole file

I need to get the information of pdf file. There is my code: PdfReader reader = new PdfReader(fileName); var info = reader.Info; I don't need to read the whole file: if there are a lot of pdf f...

Show Detail

How can I change the output file name without reading in the whole file?

So, I am using this to replace a text odirx in a file and then writing it out to another file. But I would like the output file name to be sm_0120.txt instead of sm_template2.txt as well. replacem...

Show Detail

Find and replace in a file without reading file as a string

My Question: If I'm given C:\text_file.txt as a parameter on the command line when my PERL script is called and the text_file.txt contains the text "Hello World World World", how do I replace all

Show Detail