node.js ошибка чтения файла с файлом в кодировке utf8 в Windows

#json #node.js #file-io

#json #node.js #файл-ввод-вывод #file-io

Вопрос:

Я пытаюсь загрузить файл json в формате UTF8 с диска, используя node.js (0.10.29) в Windows 8.1. Ниже приведен код, который выполняется:

 var http = require('http');
var utils = require('util');
var path = require('path');
var fs = require('fs');

var myconfig;
fs.readFile('./myconfig.json', 'utf8', function (err, data) {
    if (err) {
        console.log("ERROR: Configuration load - "   err);
        throw err;
    } else {
        try {
            myconfig = JSON.parse(data);
            console.log("Configuration loaded successfully");
        }
        catch (ex) {
            console.log("ERROR: Configuration parse - "   err);
        }


    }
});
  

Я получаю следующую ошибку, когда я запускаю это:

 SyntaxError: Unexpected token ´╗┐
    at Object.parse (native)
    ...
  

Теперь, когда я меняю кодировку файла (используя Notepad ) на ANSI, она работает без проблем.

Есть идеи, почему это так? Пока разработка выполняется в Windows, окончательное решение будет развернуто на множестве серверов, отличных от Windows, я беспокоюсь, что у меня возникнут проблемы на стороне сервера, если я, например, разверну файл ANSI в Linux.

Согласно моим поискам здесь и через Google, код должен работать в Windows, поскольку я специально говорю ему ожидать файл UTF-8.

Пример конфигурации, которую я читаю:

 {
    "ListenIP4": "10.10.1.1",
    "ListenPort": 8080
}
  

Комментарии:

1. У меня были странные вещи, связанные с чтением файлов в узле… но иногда выполнение (data «) приведет к более правильному поведению строки. Также, если это допустимый json, вы всегда можете сделать его файлом .js и выполнить module.exports = { /* data here */ }; затем потребовать его, хотя я не думаю, что это поможет с этой проблемой.

Ответ №1:

Согласно «fs.readFileSync (filename, ‘utf8’) не удаляет маркеры спецификации #1918», fs.readFile работает так, как задумано: спецификация не удаляется из заголовка файла UTF-8, если он существует.Это на усмотрение разработчика, чтобы справиться с этим.

Возможные обходные пути:

Вы получаете заголовок метки порядка байтов (BOM) файла UTF-8. Когда JSON.parse видит это, выдает синтаксическую ошибку (читай: ошибка «неожиданный символ»). Вы должны удалить метку порядка байтов из файла, прежде чем передавать его в JSON.parse :

 fs.readFile('./myconfig.json', 'utf8', function (err, data) {
    myconfig = JSON.parse(data.toString('utf8').replace(/^uFEFF/, ''));
});
// note: data is an instance of Buffer
  

Комментарии:

1. Спасибо, надеюсь, разработчики новички в node.js найдите эту страницу. Как вы можете себе представить, переход на этот уровень проблем с поиском узлов кажется немного большим. Опять же, все видео Youtube в отношении node.js разработчики действительно показывают используемые Mac-адреса. Тот факт, что я столкнулся с этой проблемой с моим первым node.js проект показывает мне, что он может пострадать от других.

2. ИМХО спецификация — это метаданные, а не часть файла. Разработчикам (и пользователям) нужен текст в файле, и это исключает спецификацию.

3. @Marc Node.js считывает файл в виде байтов (буфера), который является более низкоуровневым, чем строка (текст). Строки требуют кодировки, и если Node.js предполагая, что файл читается как таковой, мы не смогли бы легко читать большие двоичные объекты. Не делайте предположения, что все файлы являются текстовыми. По этой причине расшифровка файла остается за программой. Кроме того, знание кодировки требуется для понимания абстрагированного текстового потока, который может быть 8-разрядным ASCII, UTF-7, UTF-8, UTF-16, ISO-8859-1 и т.д. Тот факт, что спецификации нет в файле UTF-8, не означает, что нет конечного байта: по умолчанию UTF-8 равен BE .

4. Я хочу сказать, что узел не должен быть «тупее», чем notepad.exe который может открыть любой файл и правильно отобразить его. Правда, есть проблемы, но когда спецификация присутствует, она понятна и уникальна. Я не согласен с ИТ-системами, которые говорят: если мы не можем выполнить 100%-ную работу, мы выполним 0%. Нет! Приложите максимум усилий и потерпите изящную неудачу.

5. «если Node.js предполагая, что файл читается как таковой, мы не сможем легко читать большие двоичные объекты » Я полностью не согласен. Если вы указываете кодировку utf8 и есть спецификация, удалите спецификацию. Это ничего не предполагает. Вы уже сказали «это utf8». Если небезопасно предполагать, что спецификация является спецификацией, когда вы уже знаете, что файл utf8, тогда в спецификации буквально нет смысла. Либо вы видите спецификацию и знаете, что это спецификация, и вы можете безопасно удалить ее, либо вы не видите спецификацию. Нет промежуточной точки зрения, чтобы увидеть спецификацию, но не иметь возможности безопасно удалить ее.

Ответ №2:

Чтобы заставить это работать без этого, мне пришлось изменить кодировку с «UTF-8» на «UTF-8 без спецификации» с помощью Notepad (я предполагаю, что любой приличный текстовый редактор, а не Блокнот, имеет возможность выбирать этот тип кодировки).

Это решение означало, что специалисты по развертыванию могли без проблем выполнять развертывание в Unix, и я мог разрабатывать без ошибок во время чтения файла.

Что касается чтения файла, другим ответом, который я иногда получал в своих путешествиях, был знак вопроса, добавляемый перед началом содержимого файла при попытке использовать различные варианты кодирования. Естественно, при добавлении вопросительного знака или символов ANSI JSON.parse завершается с ошибкой.

Надеюсь, это кому-то поможет!

Ответ №3:

Новый ответ
Поскольку у меня была такая же проблема с несколькими разными форматами, я пошел дальше и создал npm, который пытается читать текстовые файлы и анализировать их как текст, независимо от исходного формата. (поскольку первоначальный вопрос заключался в том, чтобы прочитать .json, он идеально подойдет). (файлы без спецификации и неизвестной спецификации обрабатываются как ASCII / latin1)

https://www.npmjs.com/package/textfilereader

Поэтому измените код на

 var http = require('http');
var utils = require('util');
var path = require('path');
var fs = require('textfilereader');

var myconfig;
fs.readFile('./myconfig.json', 'utf8', function (err, data) {
    if (err) {
        console.log("ERROR: Configuration load - "   err);
        throw err;
    } else {
        try {
            myconfig = JSON.parse(data);
            console.log("Configuration loaded successfully");
        }
        catch (ex) {
            console.log("ERROR: Configuration parse - "   err);
        }
    }
});
  

Старый ответ

Столкнулся с этой проблемой сегодня и создал функцию для ее решения. Должен иметь очень маленький размер, предположим, что это лучше, чем принятое решение для замены.

 function removeBom(input) {
  // All alternatives found on https://en.wikipedia.org/wiki/Byte_order_mark
  const fc = input[0].charCodeAt(0).toString(16);
  switch (fc) {
    case 'efbbbf': // UTF-8
    case 'feff': // UTF-16 (BE)   UTF-32 (BE)
    case 'fffe': // UTF-16 (LE)
    case 'fffe0000': // UTF-32 (LE)
    case '2B2F76': // UTF-7
    case 'f7644c': // UTF-1
    case 'dd736673': // UTF-EBCDIC
    case 'efeff': // SCSU
    case 'fbee28': // BOCU-1
    case '84319533': // GB-18030
      return input.slice(1);
      break;
    default: 
      return input;
  }
}

const fileBuffer = removeBom(fs.readFileSync(filePath, "utf8"));