javascript - 使用 "fs"读取 JSON 文件会抛出 "invalid json"Node.js

标签 javascript node.js json

这让我抓狂。我不知道为什么,但是当我使用文件系统 require('fs') 读取有效的 Json 文件时,出现错误:无效的 json。这是代码:

var fs = require('fs');
const FILE_NAME = './json.json'

/*
// This way it works!
var jsonData = require('./json.json')
console.log(jsonData);
*/

async function readFile(filePath){
    return new Promise(function(resolve, reject){
        fs.readFile(filePath, 'utf8', function(err, contents) {
            if(err){
              console.log("Cant read the file " + err);
              reject(err)
            }
            else{
              resolve(contents)
            }
        })
    })
}

async function getNames(fileName){
  readFile(fileName).then(function(data){
    try {
      console.log(`Type of data: ` + typeof data);
      console.log("File data: " + data);
      return JSON.parse(data);
    } catch (error) {
      throw new Error( "Invalid JSON: " + error);
    }
  }).then(function(data){
    console.log(`FILE OBJECT: ` + data);
  }).catch(function(err){
    console.error(err);
  })
}
getNames(FILE_NAME)

这是文件内容:

{
  "name": "riko"
}

这是控制台输出:

Type of data: string
File data: {
  "name": "riko"
}
Error: Invalid JSON: SyntaxError: Unexpected token  in JSON at position 0
    at C:\Users\rojer\Desktop\Node\test\main.js:31:13

我知道我可以使用var jsonData = require('./json.json'),但是

  1. 我想知道它不起作用的原因。
  2. 如果 JSON 数据嵌入到常规文本文件中的某个位置会怎样?

enter image description here

好像有一些垃圾。

enter image description here

请帮忙。

最佳答案

这个:

Error: Invalid JSON: SyntaxError: Unexpected token  in JSON at position 0
    at C:\Users\rojer\Desktop\Node\test\main.js:31:13

tells us that there's an invisible character at the beginning of the file, probably a byte order mark (BOM), that require is handling but your code isn't. If the file is really in UTF-8, that BOM will be \xEF\xBB\xBF. Once read as UTF-8 into a JavaScript string, that will be the code point \u{FEFF} (because JavaScript strings are UTF-16 [but tolerate invalid surrogate pairs]). Update: Your binary listing of it confirms that.

I can confirm that if I have a UTF-8 JSON file with a BOM, require reads it and handles the BOM, but readFile returns the contents of the with the BOM intact, which trips up JSON.parse.

You can check for the BOM and strip it off, see *** lines:

const UTF8_BOM = "\u{FEFF}";                      // ***
async function getNames(fileName){
  readFile(fileName).then(function(data){
    try {
      console.log(`Type of data: ` + typeof data);
      if (data.startsWith(UTF8_BOM)) {            // ***
          data = data.substring(UTF8_BOM.length); // ***
      }
      console.log("File data: " + data);
      return JSON.parse(data);
    } catch (error) {
      throw new Error( "Invalid JSON: " + error);
    }
  }).then(function(data){
    console.log(`FILE OBJECT: ` + data);
  }).catch(function(err){
    console.error(err);
  })
}

或者,如果您不希望其中有 BOM,这里有一个快速但肮脏的工具,用于在 UTF-8 文件上添加/删除 BOM:

const fs = require("fs");

const UTF8_BOM = "\u{FEFF}";

const actions = new Map([
    ["-a", addBOM],
    ["-r", removeBOM],
    ["-t", toggleBOM]
]);

main();

function main() {
    const filename = process.argv[2];
    const option = process.argv[3] || "-t";
    const action = actions.get(option);

    if (!filename) {
        help();
        return;
    }

    if (!action) {
        console.error(`Invalid option ${option}`);
        help();
        return;
    }

    fs.readFile(filename, 'utf-8', (err, data) => {
        if (err) {
            console.error(`${filename}: Error reading file: ${err}`);
            return;
        }
        const hasBOM = data.startsWith(UTF8_BOM);
        action(filename, data, hasBOM);
    });
}

function writeResult(filename, data, toggle, successMessage, failMessage) {
    fs.writeFile(filename, data, "utf-8", (err) => {
        if (err) {
            console.error(`${filename}: ${failMessage}: ${err}`);
        } else {
            console.log(`${filename}: ${successMessage}${toggle ? " (toggled)" : ""}`);
        }
    });
}

function addBOM(filename, data, hasBOM, toggle) {
    if (hasBOM) {
        console.log(`${filename}: Already has a BOM`);
    } else {
        writeResult(filename, UTF8_BOM + data, toggle, "Added BOM", "Error adding BOM");
    }
}

function removeBOM(filename, data, hasBOM, toggle) {
    if (!hasBOM) {
        console.log(`${filename}: Already doesn't have a BOM`);
    } else {
        writeResult(filename, data.substring(UTF8_BOM.length), toggle, "Removed BOM", "Error removing BOM");
    }
}

function toggleBOM(filename, data, hasBOM) {
    if (hasBOM) {
        removeBOM(filename, data, hasBOM, true);
    } else {
        addBOM(filename, data, hasBOM, true);
    }
}

function help() {
    console.log("Usage: node utf8bomtoggle [filename] {options}");
    console.log("{options} can be:");
    console.log("  -t   Toggle a BOM [default]");
    console.log("  -a   Add a BOM if not present");
    console.log("  -r   Remove a BOM if present");
}

关于javascript - 使用 "fs"读取 JSON 文件会抛出 "invalid json"Node.js,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55775900/

相关文章:

javascript - 将 web3.js 与 Jest 一起使用时出错

node.js - 与 Jade 的动态链接

java - 如何防止 JSONObject 从 json.jar 将十进制数字字符串转换为 double

mysql - 如果 id 值不存在另一个表,则 SQL 连接

c# - 如何使用 Dapper 映射 MySQL JSON 列

javascript - 如何在输入时应用 ajax/json 搜索过滤器

javascript - 谷歌烛台图表上的多条线

javascript - 缺少 '()' 调用构造函数

javascript - jquery 1.7 无法将表单提交到特定的 url

authentication - 跨平台登录