Чтобы обрабатывать файл по строкам, вам просто нужно отделить чтение файла и код, который действует на этот вход. Вы можете выполнить это, буферизируя ввод, пока не нажмете новую строку. Предполагая, что у нас есть один объект JSON на строку (в основном, формат B):
var stream = fs.createReadStream(filePath, {flags: 'r', encoding: 'utf-8'});
var buf = '';
stream.on('data', function(d) {
buf += d.toString(); // when data is read, stash it in a string buffer
pump(); // then process the buffer
});
function pump() {
var pos;
while ((pos = buf.indexOf('\n')) >= 0) { // keep going while there's a newline somewhere in the buffer
if (pos == 0) { // if there's more than one newline in a row, the buffer will now start with a newline
buf = buf.slice(1); // discard it
continue; // so that the next iteration will start with data
}
processLine(buf.slice(0,pos)); // hand off the line
buf = buf.slice(pos+1); // and slice the processed data off the buffer
}
}
function processLine(line) { // here's where we do something with a line
if (line[line.length-1] == '\r') line=line.substr(0,line.length-1); // discard CR (0x0D)
if (line.length > 0) { // ignore empty lines
var obj = JSON.parse(line); // parse the JSON
console.log(obj); // do something with the data here!
}
}
Каждый раз, когда поток файлов принимает данные из файловой системы, он помещается в буфер, а затем вызывается pump
.
Если в буфере нет новой строки, pump
просто возвращается, ничего не делая. Дополнительные данные (и, возможно, новая строка) будут добавлены в буфер в следующий раз, когда поток получит данные, а затем у нас будет полный объект.
Если есть новая строка, pump
срезает буфер от начала до новой строки и передать его на process
. Затем он снова проверяет, есть ли в буфере новая строка (цикл while
). Таким образом, мы можем обрабатывать все строки, которые были прочитаны в текущем фрагменте.
Наконец, process
вызывается один раз для каждой строки ввода. Если он присутствует, он удаляет символ возврата каретки (чтобы избежать проблем с концами строк & ndash; LF vs CRLF), а затем вызывает JSON.parse
одну строку. На этом этапе вы можете делать все, что вам нужно, с вашим объектом.
Обратите внимание, что JSON.parse
строго относится к тому, что он принимает в качестве входных данных; вы должны указывать ваши идентификаторы и строковые значения с двойными кавычками . Другими словами, {name:'thing1'}
выдаст ошибку; вы должны использовать {"name":"thing1"}
.
Поскольку за один раз в памяти будет больше, чем кусок данных, это будет чрезвычайно эффективным с точки зрения памяти. Это также будет очень быстро. Быстрый тест показал, что я обработал 10 000 строк в возрасте до 15 мс.
Этот сценарий должен сделать. Это - (почти) чистый Удар. seq
часть может быть заменена, если абсолютно чистый удар требуется.
, Так как Удар, по-видимому, использует подписанные 4-байтовые целые числа с двумя дополнениями, сценарий ограничен/8 максимумом маски. Я нашел диапазоны больше, чем/16 непрактичный так или иначе, таким образом, это не беспокоит меня вообще. Если кто-то знает простой способ преодолеть это, разделите:)
#!/usr/bin/env bash
base=${1%/*}
masksize=${1#*/}
[ $masksize -lt 8 ] && { echo "Max range is /8."; exit 1;}
mask=$(( 0xFFFFFFFF << (32 - $masksize) ))
IFS=. read a b c d <<< $base
ip=$(( ($b << 16) + ($c << 8) + $d ))
ipstart=$(( $ip & $mask ))
ipend=$(( ($ipstart | ~$mask ) & 0x7FFFFFFF ))
seq $ipstart $ipend | while read i; do
echo $a.$(( ($i & 0xFF0000) >> 16 )).$(( ($i & 0xFF00) >> 8 )).$(( $i & 0x00FF ))
done
Использование:
./script.sh 192.168.13.55/22
Проверенный с версией 4.4.23 Удара. YMMV.