Странные символы Юникода при чтении файла в приложении node.js

Я пытаюсь написать приложение node, которое считывает набор файлов, разбивает их на строки и помещает строки в массив. Довольно просто. Он работает с несколькими файлами, за исключением некоторых файлов SQL, с которыми я работаю. По какой-то причине я, кажется, получаю какой-то вывод Unicode, когда я разделяю строки. Приложение выглядит примерно так:

fs = require("fs");
var data = fs.readFileSync("test.sql", "utf8");
console.log(data);
lines = data.split("\n");
console.log(lines);

Входной файл выглядит примерно так:

use whatever
go

Вывод выглядит следующим образом:

��use whatever
go

[ '��u\u0000s\u0000e\u0000 \u0000w\u0000h\u0000a\u0000t\u0000e\u0000v\u0000e\u0000r\u0000',
  '\u0000g\u0000o\u0000',
  '\u0000' ]

Как видите, в начале файла есть какой-то нераспознанный символ. После чтения данных и их прямого вывода все выглядит нормально, за исключением этого символа. Однако, если я затем попытаюсь разбить его на строки, я получу все эти юникод-подобные символы. В основном это все настоящие символы с «\ u0000» в начале каждого из них.

Я понятия не имею, что здесь происходит, но, похоже, это как-то связано с символами в самом файле. Если я скопирую и вставлю текст файла в другой новый файл и запущу приложение в новом файле, он будет работать нормально. Я предполагаю, что все, что вызывает эту проблему, удаляется в процессе копирования и вставки.


person d512    schedule 18.01.2013    source источник


Ответы (4)


Ваш файл имеет формат UTF-16 Little Big Endian, а не UTF-8.

var data = fs.readFileSync("test.sql", "utf16le"); //Not sure if this eats the BOM

К сожалению, node.js поддерживает только UTF-16 Little Endian или UTF-16LE (не могу быть уверен, читая документы, между ними есть небольшая разница, а именно то, что UTF-16LE не использует спецификации), поэтому вам нужно использовать iconv или преобразовать файл в UTF-8 другим способом.

Пример:

var Iconv  = require('iconv').Iconv,
    fs = require("fs");

var buffer = fs.readFileSync("test.sql"),
    iconv = new Iconv( "UTF-16", "UTF-8");

var result = iconv.convert(buffer).toString("utf8");
person Esailija    schedule 18.01.2013
comment
Вау, ты попал. Спасибо. Итак, просто из любопытства, как вы узнали, что этот файл имеет кодировку UTF-16 с обратным порядком байтов? Есть ли способ обнаружить это в узле? Я обрабатываю несколько файлов, и они не все закодированы одинаково. - person d512; 18.01.2013
comment
@user1334007 user1334007 из-за нулей в четных позициях, если бы они были в нечетных позициях, это было бы прямым порядком байтов. Автоматическое обнаружение кодировки требует некоторой эвристики путем анализа нулевых позиций, чтобы определить, какие UTF-16 и UTF-8 имеют очень уникальные шаблоны. Но большинство других кодировок невозможно обнаружить, не попробовав и не посмотрев, правильно ли выводится текст. - person Esailija; 18.01.2013
comment
К вашему сведению, я нашел кое-что, что выглядит многообещающе для обнаружения кодировки с помощью узла: github.com/mooz/ node-icu-charset-detector. Еще не пробовал, но если получится, отчитаюсь. - person d512; 18.01.2013
comment
@ user1334007 да, но учтите, что надежно определить кодировку невозможно. Однако стоит попробовать, если у вас много файлов и/или вы не можете обнаружить их вручную. - person Esailija; 18.01.2013
comment
Да, я попробовал и обнаружил, что это не очень помогает. В конце концов я переписал инструмент на .NET, и он работает намного лучше. - person d512; 19.01.2013
comment
Нули находятся в нечетных позициях, поэтому это действительно прямой порядок следования байтов (что является более распространенной формой UTF-16, которую предпочитает Windows), поэтому проблем быть не должно. - person bobince; 19.01.2013
comment
@bobince да, я не заметил u после того, как bom :X исправит - person Esailija; 19.01.2013
comment
FWIW: анализ текстового файла, экспортированного из сценария Excel VBA как XlFileFormat.xlUnicodeText, похоже, также является UTF-16 LE, поэтому мне нужно было только указать формат utf16le в узле (затем разделить на \r\n для отдельных строк ). Спасибо за этот ответ! - person Tyler; 21.12.2013
comment
С помощью Visual Studio Code очень легко преобразовать как кодировку файлов, так и окончания строк. Внизу есть селекторы и оттуда можно быстро пересохранить файл :) - person jocull; 25.10.2020

Возможно, это BOM (знак порядка байтов)? Убедитесь, что вы сохраняете свои файлы без BOM или включаете код для удаления BOM.

BOM обычно невидим в текстовых редакторах.

Я знаю, что в Notepad++ есть функция, позволяющая легко удалить BOM из файла. Encoding > Encode in UTF-8 without BOM.

person Halcyon    schedule 18.01.2013
comment
Повороты первого символа - это спецификация. Однако его удаление, похоже, не решает проблему . - person d512; 18.01.2013
comment
Я использовал Notepad++, чтобы преобразовать свой файл в UTF-8, затем прочитал файл, используя fs.readFileSync, чтобы избавиться от SyntaxError: Unexpected token — в JSON в позиции 0 - person Zee; 17.04.2021

Я сделал следующее в командной строке Windows, чтобы преобразовать порядок байтов:

type file.txt > file2.txt
person Chong Lip Phang    schedule 16.07.2018
comment
С помощью этого решения была устранена не только моя проблема с разбором файла журнала Apache, но и размер файла уменьшился почти до половины его первоначального размера. - person Farid Rn; 14.04.2020

Используйте облегченную версию Iconv-lite.

var result= "";
var iconv = require('iconv-lite');
var stream = fs.createReadStream(sourcefile)
    .on("error",function(err){
        //handle error
    })
    .pipe(iconv.decodeStream('win1251'))
    .on("error",function(err){
        //handle error
    })
    .on("data",function(data){
        result += data;
    })
    .on("end",function(){
       //use result
    });
person Vikas    schedule 18.05.2017