问题
I got a very nice answer on here about how to clear a line / delete a line in a file without having to truncate the file or replace the file with a new version of the file, here's the Python code:
#!/usr/bin/env python
import re,os,sys
logfile = sys.argv[1]
regex = sys.argv[2]
pattern = re.compile(regex)
with open(logfile,"r+") as f:
while True:
old_offset = f.tell()
l = f.readline()
if not l:
break
if pattern.search(l):
# match: blank the line
new_offset = f.tell()
if old_offset > len(os.linesep):
old_offset-=len(os.linesep)
f.seek(old_offset)
f.write(" "*(new_offset-old_offset-len(os.linesep)))
this script can be called like:
./clear-line.py <file> <pattern>
For educational purposes, I am trying to figure out if I can write this in Node.js. I can certainly read a file with Node.js line-by-line. But I am not sure if Node.js has the equivalent calls for tell/seek in this case.
the equivalent for write is surely
https://nodejs.org/api/fs.html#fs_fs_write_fd_buffer_offset_length_position_callback
Here is my attempt
#!/usr/bin/env node
const readline = require('readline');
const fs = require('fs');
const file = process.argv[2];
const rgx = process.argv[3];
const fd = fs.openSync(file, 'r+');
const rl = readline.createInterface({
input: fs.createReadStream(null, {fd: fd})
});
let position = 0;
const onLine = line => {
position += line.length;
if (String(line).match(rgx)) {
let len = line.length;
rl.close();
rl.removeListener('line', onLine);
// output the line that will be replaced/removed
process.stdout.write(line);
fs.write(fd, new Array(len + 1).join(' '), position, 'utf8', err => {
if (err) {
process.stderr.write(err.stack || err);
process.exit(1);
}
else {
process.exit(0);
}
});
}
};
rl.on('line', onLine);
It's not quite right - I don't think I am calculating the offset/position correctly. Perhaps someone who know both Python and Node can help me out. I am not very familiar with calculating position/offset in files, especially in terms of buffers.
Here is the data in a text file that I am working with. All I want to do is read the first line that is not empty, and then remove that line from the file and write that line to stdout.
This could really any non-whitespace data, but here is the JSON that I am working with:
{"dateCreated":"2016-12-26T09:52:03.250Z","pid":5371,"count":0,"uid":"7133d123-e6b8-4109-902b-7a90ade7c655","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:03.290Z","pid":5371,"count":1,"uid":"e881b0a9-8c28-42bb-8a9d-8109587777d0","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:03.390Z","pid":5371,"count":2,"uid":"065e51ff-14b8-4454-9ae5-b85152cfcb64","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:03.491Z","pid":5371,"count":3,"uid":"5af80a95-ff9d-4252-9c4e-0e421fd9320f","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:03.595Z","pid":5371,"count":4,"uid":"961e578f-288b-413c-b933-b791f833c037","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:03.696Z","pid":5371,"count":5,"uid":"a65cbf78-2ea1-4c3a-9beb-b4bf56e83a6b","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:03.799Z","pid":5371,"count":6,"uid":"d411e917-ad25-455f-9449-ae4d31c7b1ad","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:03.898Z","pid":5371,"count":7,"uid":"46f8841d-c86c-43f2-b440-8ab7feea7527","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:04.002Z","pid":5371,"count":8,"uid":"81b5ce7e-2f4d-4acb-884c-442c5ac4490f","isRead":false,"line":"foo bar baz"}
{"dateCreated":"2016-12-26T09:52:04.101Z","pid":5371,"count":9,"uid":"120ff45d-74e7-464e-abd5-94c41e3cd089","isRead":false,"line":"foo bar baz"}
回答1:
You should take into consideration the newline character at the end of each line, that is not included in the 'line' you're getting via the readline module. That is, you should update position to position += (line.length + 1)
, and then when writing, just use position
(without the -1
).
回答2:
Ok, I think I got it, but if someone has any beef with this please feel free to critique. It's close, but it needs some fine tuning I think, there seems to be an off-by-one error or something like that.
#!/usr/bin/env node
const readline = require('readline');
const fs = require('fs');
const file = process.argv[2];
const rgx = new RegExp(process.argv[3]);
const fd = fs.openSync(file, 'r+');
const rl = readline.createInterface({
input: fs.createReadStream(null, {fd: fd})
});
let position = 0;
const onLine = line => {
if (String(line).match(rgx)) {
let len = line.length;
rl.close();
rl.removeListener('line', onLine);
// output the line that will be replaced/removed
process.stdout.write(line + '\n');
fs.write(fd, new Array(len + 1).join(' '), position, 'utf8',
(err, written, string) => {
if (err) {
process.stderr.write(err.stack || err);
return process.exit(1);
}
else {
process.exit(0);
}
});
}
position += (line.length + 1); // 1 is length of \n character
};
rl.on('line', onLine);
来源:https://stackoverflow.com/questions/41329374/how-to-translate-this-python-code-to-node-js