Этот вопрос предполагает путаницу в отношении API асинхронной потоковой передачи и, по-видимому, задает как минимум три вещи.
- Как мне получить
output
, чтобы содержать массив массивов, представляющихпроанализировал данные CSV?
То, что output
никогда не будет существовать на верхнем уровне, как надеются вы (и многие другие программисты), из-за того, как работают асинхронные API.Все данные, собранные аккуратно в одном месте, могут существовать только в функции обратного вызова.Следующая лучшая вещь синтаксически это const output = await somePromiseOfOutput()
, но это может произойти только в async function
и только если мы переключимся с потоков на обещания.Это все возможно, и я упоминаю об этом, чтобы вы могли проверить это позже самостоятельно.Я предполагаю, что вы хотите придерживаться потоков.
Массив, состоящий из всех строк, может существовать только после чтения всего потока.Вот почему все строки доступны только в авторском примере «Stream API» только в обратном вызове .on('end', ...)
.Если вы хотите что-то сделать со всеми присутствующими строками одновременно, вам нужно будет сделать это в конце обратного вызова.
С https://csv.js.org/parse/api/ обратите внимание, что автор:
- использует обратный вызов on для чтения, чтобы поместить отдельные записи в ранее пустой массив, определенный с внешним именем
output
. - использует обратный вызов on для сообщения об ошибках
- использует обратный вызов on end для сравнения всех накопленных записей в выводе с ожидаемым результатом
...
const output = []
...
parser.on('readable', function(){
let record
while (record = parser.read()) {
output.push(record)
}
})
// Catch any error
parser.on('error', function(err){
console.error(err.message)
})
// When we are done, test that the parsed output matched what expected
parser.on('end', function(){
assert.deepEqual(
output,
[
[ 'root','x','0','0','root','/root','/bin/bash' ],
[ 'someone','x','1022','1022','','/home/someone','/bin/bash' ]
]
)
})
Что касается цели взаимодействия с sqlite, это по сути создание настраиваемой конечной точки потоковой передачи.
В этом случае использования реализует настроенный поток записи , который принимает выходные данные синтаксического анализатора и отправляет строки в базу данных.
Затем вы просто соединяете вызовы по конвейерукак
fs.createReadStream(__dirname+'/fs_read.csv')
.pipe(parser)
.pipe(your_writable_stream)
Осторожно : Этот код возвращается немедленно.Он не ждет окончания операций.Он взаимодействует со скрытым циклом событий, внутренним для node.js.Цикл событий часто сбивает с толку новых разработчиков, которые приходят с другого языка, привыкли к более императивному стилю и пропускают эту часть своего обучения node.js.
Реализация такого настраиваемого потока записи может быть затрудненаи оставлено в качестве упражнения для читателя.Будет проще, если синтаксический анализатор выдает строку, а затем средство записи может быть написано для обработки отдельных строк.Удостоверьтесь, что вы можете как-то замечать ошибки и выдавать соответствующие исключения, иначе вы будете прокляты с неполными результатами и без предупреждения или причины.
Хакерским способом было бы заменить console.log(data)
в let parser = ...
настраиваемой функцией writeRowToSqlite(data)
, которую вам все равно придется написать для реализации пользовательского потока.Из-за асинхронных проблем с API, использование return data
не дает ничего полезного.Конечно, как вы видели, данные не помещаются в выходную переменную.
Относительно того, почему
output
в вашей измененной публикации не содержит данных ...
К сожалению, как вы обнаружили, это обычно неправильно:
const output = fs.createReadStream(__dirname + "/users.csv").pipe(parser);
console.log(output);
Здесь переменная output
будет ReadableStream , которая не совпадает с данными, содержащимися в читаемом потоке.Проще говоря, это как когда у вас есть файл в вашей файловой системе, и вы можете получить все виды системной информации о файле, но доступ к содержимому в файле осуществляется через другой вызов.