Javascript-форум (https://javascript.ru/forum/)
-   Node.JS (https://javascript.ru/forum/node-js-io-js/)
-   -   Перекодировать данные из MongoDB в файл csv (https://javascript.ru/forum/node-js-io-js/82612-perekodirovat-dannye-iz-mongodb-v-fajjl-csv.html)

ksa 31.05.2021 17:13

Перекодировать данные из 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()
	}
});

ksa 02.06.2021 14:26

Пробую просто перекодировать строку по примерам из инета...

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 варианта - кракозябры. :(

ksa 02.06.2021 19:11

Даже пример в самой 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

MallSerg 02.06.2021 21:28

iconv - замечательно работает.

Сталкивался с такой проблемой.
Любой вызов автоматического приведения типов превращает буфер в строку без реальной конвертации 8 битной кодировки cp1251 в 16 битную UTF16 используемой движком для хранения строк.

Например " 'str ' + str " токсичное выражение т.к. str должно быть приведено к строке и как следствие превращается в мусор.

Самый простой способ борьбы избегать автоматического приведения типов.

А вообще пошаговая отладка хорошо показывает в какой момент строка/буфер превращается в мусор.

ksa 02.06.2021 21:31

Цитата:

Сообщение от MallSerg
замечательно работает

Тогда поправь мой пример, так чтобы в файле были русские буквы в ВИН-кодировке...

Цитата:

Сообщение от MallSerg
Например " 'str ' + str " токсичное выражение т.к. str должно быть приведено к строке и как следствие превращается в мусор.

У меня нет таких строк...
Все обычные слова на русском но только в кодировке UTF-8. Это данные из MongoDB.

В примере - просто строка.

ksa 02.06.2021 21:36

Цитата:

Сообщение от MallSerg
Например " 'str ' + str " токсичное выражение т.к. str должно быть приведено к строке и как следствие превращается в мусор.

Привел все переменные "к строке"...
Но результат не поменялся. :(

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')
})

MallSerg 02.06.2021 21:53

В том то и дело что любое приведение к строке превращает буфер в мусор.

т.е. "str.toString()" превратит строку в мусор.

ksa 02.06.2021 22:06

Такое вот сработало! :)

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')
})

ksa 02.06.2021 22:16

Цитата:

Сообщение от MallSerg
т.е. "str.toString()" превратит строку в мусор.

Пишут что вполне себе нормальное действие... :-?
https://nodejsdev.ru/doc/buffer/#_4

MallSerg 03.06.2021 00:21

Действие нормальное но работает не так как ты ожидаешь.

Проблема не в nodeJS а в движке V8 и его реализации работы со строками.
В V8 символы в строке выравниваются по границе uint16_t для оптимизации работы со строками и кирилица во внутреннем представлении кодируется двумя байтами что бы работали сравнения регулярные выражение и прочее.

И в момент когда данные буфера (char*) преобразуются во внутренне представление движка (uint16_t*) они просто выравниваются по границе uint16_t для латиницы это нормально а для символов которые должны кодироваться двумя байтами это фатально и возникает ошибка с однобайтовыми национальными кодировками (например cp1251).

>> Такое вот сработало!
Потому что буфер не приводился к строке.


Часовой пояс GMT +3, время: 21:59.