Я хотел решить эту же проблему, в основном то, что было бы в Perl:
while (<>) {
process_line($_);
}
Мой вариант использования был просто автономным сценарием, а не сервером, поэтому синхронность была в порядке. Это были мои критерии:
- Минимальный синхронный код, который можно использовать во многих проектах.
- Нет ограничений на размер файла или количество строк.
- Нет ограничений на длину строк.
- Может обрабатывать полный Юникод в UTF-8, включая символы за пределами BMP.
- Способен обрабатывать * nix и окончания строк Windows (Mac старого образца мне не нужен).
- Символы конца строки для включения в строки.
- Может обрабатывать последнюю строку с символами конца строки или без них.
- Не использовать внешние библиотеки, не включенные в дистрибутив node.js.
Это проект для меня, чтобы почувствовать низкоуровневый код типа сценариев в node.js и решить, насколько он жизнеспособен в качестве замены для других языков сценариев, таких как Perl.
После удивительных усилий и нескольких неудачных попыток вот код, который я придумал. Это довольно быстро, но менее тривиально, чем я ожидал: (раскошелиться на GitHub)
var fs = require('fs'),
StringDecoder = require('string_decoder').StringDecoder,
util = require('util');
function lineByLine(fd) {
var blob = '';
var blobStart = 0;
var blobEnd = 0;
var decoder = new StringDecoder('utf8');
var CHUNK_SIZE = 16384;
var chunk = new Buffer(CHUNK_SIZE);
var eolPos = -1;
var lastChunk = false;
var moreLines = true;
var readMore = true;
// each line
while (moreLines) {
readMore = true;
// append more chunks from the file onto the end of our blob of text until we have an EOL or EOF
while (readMore) {
// do we have a whole line? (with LF)
eolPos = blob.indexOf('\n', blobStart);
if (eolPos !== -1) {
blobEnd = eolPos;
readMore = false;
// do we have the last line? (no LF)
} else if (lastChunk) {
blobEnd = blob.length;
readMore = false;
// otherwise read more
} else {
var bytesRead = fs.readSync(fd, chunk, 0, CHUNK_SIZE, null);
lastChunk = bytesRead !== CHUNK_SIZE;
blob += decoder.write(chunk.slice(0, bytesRead));
}
}
if (blobStart < blob.length) {
processLine(blob.substring(blobStart, blobEnd + 1));
blobStart = blobEnd + 1;
if (blobStart >= CHUNK_SIZE) {
// blobStart is in characters, CHUNK_SIZE is in octets
var freeable = blobStart / CHUNK_SIZE;
// keep blob from growing indefinitely, not as deterministic as I'd like
blob = blob.substring(CHUNK_SIZE);
blobStart -= CHUNK_SIZE;
blobEnd -= CHUNK_SIZE;
}
} else {
moreLines = false;
}
}
}
Вероятно, это может быть очищено дальше, это было результатом проб и ошибок.