Перекодировать данные из MongoDB в файл csv
Хочу перекодировать данные из MongoDB (utf-8) в файл csv (windows-1251)...
Нашел два примера с использованием encoding и iconv-lite. Но какие бы комбинации на пробовал - файл получается с "кракозябрами". :( Может подскажите как получить файл в нужной (win) кодировке? const mongojs = require('mongojs') const fs = require("fs"); const tunnel = require('tunnel-ssh'); const encoding = require('encoding') const iconv = require("iconv-lite") const cnf = JSON.parse(fs.readFileSync('./config.json')) const config = { host: cnf.host, port: cnf.port, username: cnf.username, agent : process.env.SSH_AUTH_SOCK, privateKey: fs.readFileSync(cnf.keyFile), dstPort: cnf.dstPort }; const server = tunnel(config, function (error, server) { if (error) return console.log("SSH не подключился", error) const db = mongojs('test') const cl = db.collection('product') //const file = fs.createWriteStream('product.csv', 'ascii') const file = fs.createWriteStream('product.csv', 'utf-8') file.on('error', err => { console.log('Ошибка записи файла', err) }) const q = {} const fld = { title: 1 } const cur = cl.find(q, fld).sort({title: 1}) cur.on('data', (doc) => { //const val = iconv.decode(doc.title, "win1251") //const val = encoding.convert(doc.title, 'WINDOWS-1251', 'UTF-8') //file.write(val + ';\n') file.write(doc.title + ';\n') }) cur.on('error', err => { end() console.log('Ошибка чтения данных', err) }) cur.on('end', () => { end() console.log('Все') }) const end = () => { db.close() file.end() } }); |
Пробую просто перекодировать строку по примерам из инета...
const encoding = require('encoding') const iconv = require("iconv-lite") const fs = require("fs"); const str = 'Пример текста в UTF-8' const val1 = encoding.convert(str, 'WINDOWS-1251', 'UTF-8') const bfr = Buffer.from(str) const val2 = iconv.encode(bfr, "win1251") const val3 = iconv.decode(bfr, "win1251") console.log('1 ', val1) console.log('2 ', val2) console.log('3 ', val3) const opt = { encoding: 'ascii' } fs.appendFile('test.txt', '1. ' + val1 + '\n', opt, err => { if (!err) console.log('Записано 1') }) fs.appendFile('test.txt', '2. ' + val2 + '\n', opt, err => { if (!err) console.log('Записано 2') }) fs.appendFile('test.txt', '3. ' + val3 + '\n', opt, err => { if (!err) console.log('Записано 3') }) Все 3 варианта - кракозябры. :( |
Даже пример в самой iconv-lite не работает... :(
const iconv = require('iconv-lite'); const fs = require('fs') // Convert from an encoded buffer to a js string. let buf = Buffer.from([0x68, 0x65, 0x6c, 0x6c, 0x6f]) let str = iconv.decode(buf, 'win1251'); // Convert from a js string to an encoded buffer. buf = iconv.encode('Пример строки преобразованной в буфер', 'win1251'); // Check if encoding is supported const val = iconv.encodingExists("us-ascii") fs.appendFile('temp.txt', 'str ' + str + '\n', {encoding: 'ascii'}, err => { if (!err) console.log('Записано str') }) fs.appendFile('temp.txt', 'buf ' + buf + '\n', {encoding: 'ascii'}, err => { if (!err) console.log('Записано buf') }) Т.е. строки с английскими буквами отображаются... А с русскими (что как раз нужно) - фигу. :-E |
iconv - замечательно работает.
Сталкивался с такой проблемой. Любой вызов автоматического приведения типов превращает буфер в строку без реальной конвертации 8 битной кодировки cp1251 в 16 битную UTF16 используемой движком для хранения строк. Например " 'str ' + str " токсичное выражение т.к. str должно быть приведено к строке и как следствие превращается в мусор. Самый простой способ борьбы избегать автоматического приведения типов. А вообще пошаговая отладка хорошо показывает в какой момент строка/буфер превращается в мусор. |
Цитата:
Цитата:
Все обычные слова на русском но только в кодировке UTF-8. Это данные из MongoDB. В примере - просто строка. |
Цитата:
Но результат не поменялся. :( const iconv = require('iconv-lite'); const fs = require('fs') // Convert from an encoded buffer to a js string. let buf = Buffer.from([0x68, 0x65, 0x6c, 0x6c, 0x6f]) let str = iconv.decode(buf, 'win1251'); // Convert from a js string to an encoded buffer. buf = iconv.encode('Пример строки преобразованной в буфер', 'win1251'); // Check if encoding is supported const val = iconv.encodingExists("us-ascii") console.log('encodingExists ', val) fs.appendFile('temp.txt', 'str ' + str.toString() + '\n', {encoding: 'ascii'}, err => { if (!err) console.log('Записано str') }) fs.appendFile('temp.txt', 'buf ' + buf.toString() + '\n', {encoding: 'ascii'}, err => { if (!err) console.log('Записано buf') }) |
В том то и дело что любое приведение к строке превращает буфер в мусор.
т.е. "str.toString()" превратит строку в мусор. |
Такое вот сработало! :)
const iconv = require('iconv-lite'); const fs = require('fs') // Convert from a js string to an encoded buffer. buf = iconv.encode('Пример строки преобразованной в буфер', 'win1251'); fs.appendFile('temp.txt', buf, {encoding: 'ascii'}, err => { if (!err) console.log('Записано buf') }) |
Цитата:
https://nodejsdev.ru/doc/buffer/#_4 |
Действие нормальное но работает не так как ты ожидаешь.
Проблема не в nodeJS а в движке V8 и его реализации работы со строками. В V8 символы в строке выравниваются по границе uint16_t для оптимизации работы со строками и кирилица во внутреннем представлении кодируется двумя байтами что бы работали сравнения регулярные выражение и прочее. И в момент когда данные буфера (char*) преобразуются во внутренне представление движка (uint16_t*) они просто выравниваются по границе uint16_t для латиницы это нормально а для символов которые должны кодироваться двумя байтами это фатально и возникает ошибка с однобайтовыми национальными кодировками (например cp1251). >> Такое вот сработало! Потому что буфер не приводился к строке. |
Часовой пояс GMT +3, время: 11:42. |