【问题标题】:JSON.stringify throws RangeError: Invalid string length for huge objectsJSON.stringify 抛出 RangeError: Invalid string length for large objects
【发布时间】:2015-05-24 09:56:21
【问题描述】:

正如标题所暗示的,我正在尝试在我的 Node.js 应用程序中使用 JSON.stringify 对巨大的 JavaScript 对象进行字符串化。这些对象 - 再次 - 巨大(数十兆字节),它们不包含任何功能。我需要将序列化的对象写入文件。我现在得到的是这样的:

RangeError: Invalid string length
  at Object.stringify (native)
  at stringifyResult (/my/file.js:123:45) -> line where I use JSON.stringify

知道如何解决这个问题吗?

【问题讨论】:

  • 这可能只是宇宙在暗示你以不同的方式解决问题。
  • 也就是说,如果您正在为输出准备数据结构,您可以编写自己的 JSON 序列化程序,以增量方式写入输出流,而不是创建单个大字符串。这不会超级简单,但也不会超级难。
  • 我认为有流式传输或缓冲的 JSON 反序列化器。
  • 寻找类似的答案,除了 javascript 客户端(无节点)。同时,这是您的问题的答案,@boris:stackoverflow.com/questions/24153996/…

标签: javascript json node.js stringify


【解决方案1】:

我发现 JSONStream 是原生 JSON.stringify 的可靠替代方案,它适用于大型对象。例如:

var fileSystem = require( "fs" );
var JSONStream = require( "JSONStream" );
var records = [
    { id: 1, name: "Terminator" },
    { id: 2, name: "Predator" },
    { id: 3, name: "True Lies" },
    { id: 4, name: "Running Man" },
    { id: 5, name: "Twins" }
    // .... hundreds of thousands of records ....
];

var transformStream = JSONStream.stringify();
var outputStream = fileSystem.createWriteStream( __dirname + "/data.json" );
transformStream.pipe( outputStream );    
records.forEach( transformStream.write );
transformStream.end();

outputStream.on(
    "finish",
    function handleFinish() {
        console.log("Done");
    }
);

here获取示例代码。

【讨论】:

    【解决方案2】:

    正如@sandeepanu 所提到的,there's a great little solution by @madhunimmo 如果您想对一个巨大的数组进行字符串化。一次只对一个元素进行字符串化:

    let out = "[" + yourArray.map(el => JSON.stringify(el)).join(",") + "]";
    

    如果您尝试对具有大量键/属性的对象进行字符串化,那么您可以先在其上使用Object.entries() 将其转换为键/值对数组:

    let out = "[" + Object.entries(yourObject).map(el => JSON.stringify(el)).join(",") + "]";
    

    如果这仍然不起作用,那么您可能希望使用流式处理方法,尽管您可以将数组分割成多个部分并存储为多个 jsonl(每行一个对象)文件:

    // untested code
    let numFiles = 4;
    for(let i  = 0; i < numFiles; i++) {
      let out = arr.slice((i/numFiles)*arr.length, ((i+1)/numFiles)*arr.length).map(el => JSON.stringify(el)).join(",");
      // add your code to store/save `out` here
    }
    

    一种流式传输方法(新的,目前仅在 Chrome 中支持,但可能会出现在其他浏览器,甚至是某种形式的 Deno 和 Node.js)是使用File System Access API。代码看起来像这样:

    // untested code
    const dirHandle = await window.showDirectoryPicker();
    const fileHandle = await dirHandle.getFileHandle('yourData.jsonl', { create: true });
    const writable = await fileHandle.createWritable();
    for(let el of yourArray) {
      await writable.write(JSON.stringify(el)+"\n");
    }
    await writable.close();
    

    【讨论】:

      【解决方案3】:

      我也看到了这个无用/误导性的 nodejs 错误消息,所以我在 nodejs github 上预订了一个问题

      RangeError: Invalid string length --- it should be saying Out Of Memory

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-22
      • 1970-01-01
      • 1970-01-01
      • 2011-12-27
      • 2022-01-18
      • 2020-09-29
      相关资源
      最近更新 更多