Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 31.05.2021, 17:13
Аватар для ksa
ksa ksa вне форума
CacheVar
Отправить личное сообщение для ksa Посмотреть профиль Найти все сообщения от ksa
 
Регистрация: 19.08.2010
Сообщений: 14,123

Перекодировать данные из 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()
	}
});
Ответить с цитированием
  #2 (permalink)  
Старый 02.06.2021, 14:26
Аватар для ksa
ksa ksa вне форума
CacheVar
Отправить личное сообщение для ksa Посмотреть профиль Найти все сообщения от ksa
 
Регистрация: 19.08.2010
Сообщений: 14,123

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

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 варианта - кракозябры.
Ответить с цитированием
  #3 (permalink)  
Старый 02.06.2021, 19:11
Аватар для ksa
ksa ksa вне форума
CacheVar
Отправить личное сообщение для ksa Посмотреть профиль Найти все сообщения от ksa
 
Регистрация: 19.08.2010
Сообщений: 14,123

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

Т.е. строки с английскими буквами отображаются... А с русскими (что как раз нужно) - фигу.
Ответить с цитированием
  #4 (permalink)  
Старый 02.06.2021, 21:28
Аватар для MallSerg
Профессор
Отправить личное сообщение для MallSerg Посмотреть профиль Найти все сообщения от MallSerg
 
Регистрация: 07.03.2011
Сообщений: 1,127

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

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

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

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

А вообще пошаговая отладка хорошо показывает в какой момент строка/буфер превращается в мусор.
Ответить с цитированием
  #5 (permalink)  
Старый 02.06.2021, 21:31
Аватар для ksa
ksa ksa вне форума
CacheVar
Отправить личное сообщение для ksa Посмотреть профиль Найти все сообщения от ksa
 
Регистрация: 19.08.2010
Сообщений: 14,123

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

Сообщение от MallSerg
Например " 'str ' + str " токсичное выражение т.к. str должно быть приведено к строке и как следствие превращается в мусор.
У меня нет таких строк...
Все обычные слова на русском но только в кодировке UTF-8. Это данные из MongoDB.

В примере - просто строка.
Ответить с цитированием
  #6 (permalink)  
Старый 02.06.2021, 21:36
Аватар для ksa
ksa ksa вне форума
CacheVar
Отправить личное сообщение для ksa Посмотреть профиль Найти все сообщения от ksa
 
Регистрация: 19.08.2010
Сообщений: 14,123

Сообщение от 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')
})
Ответить с цитированием
  #7 (permalink)  
Старый 02.06.2021, 21:53
Аватар для MallSerg
Профессор
Отправить личное сообщение для MallSerg Посмотреть профиль Найти все сообщения от MallSerg
 
Регистрация: 07.03.2011
Сообщений: 1,127

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

т.е. "str.toString()" превратит строку в мусор.
Ответить с цитированием
  #8 (permalink)  
Старый 02.06.2021, 22:06
Аватар для ksa
ksa ksa вне форума
CacheVar
Отправить личное сообщение для ksa Посмотреть профиль Найти все сообщения от ksa
 
Регистрация: 19.08.2010
Сообщений: 14,123

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

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')
})
Ответить с цитированием
  #9 (permalink)  
Старый 02.06.2021, 22:16
Аватар для ksa
ksa ksa вне форума
CacheVar
Отправить личное сообщение для ksa Посмотреть профиль Найти все сообщения от ksa
 
Регистрация: 19.08.2010
Сообщений: 14,123

Сообщение от MallSerg
т.е. "str.toString()" превратит строку в мусор.
Пишут что вполне себе нормальное действие...
https://nodejsdev.ru/doc/buffer/#_4
Ответить с цитированием
  #10 (permalink)  
Старый 03.06.2021, 00:21
Аватар для MallSerg
Профессор
Отправить личное сообщение для MallSerg Посмотреть профиль Найти все сообщения от MallSerg
 
Регистрация: 07.03.2011
Сообщений: 1,127

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

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

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

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



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как правильно сохранить загруженный файл? 2chan Node.JS 10 03.04.2016 23:11
Как сохранить данные в файл? Возможно такое на JavaScript? Forgott Общие вопросы Javascript 35 26.06.2015 19:11
Не уходят данные на файл user_auth.php faxll AJAX и COMET 0 11.07.2014 14:26
Как отправить данные в .php файл на другой сервер ? lamer AJAX и COMET 2 04.04.2012 23:55
Не совсем обычный фрейм и выезжающий текст при наводе на картинку. amaz245 Элементы интерфейса 35 25.12.2010 17:29