JSON.stringify抛出RangeError:巨大对象的字符串长度无效

bor*_*kur 27 javascript json node.js stringify

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

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

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

Sco*_*and 12

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

RangeError:字符串长度无效---它应该是Out Of Memory

  • 另请检查:https://dev.to/madhunimmo/json-stringify-rangeerror-invalid-string-length-3977 (2认同)

joe*_*joe 9

正如 @sandeepanu 所提到的,如果你想对一个巨大的数组进行字符串化,@madhunimmo 有一个很棒的小解决方案。一次只字符串化一个元素:

let out = "[" + yourArray.map(el => JSON.stringify(el)).join(",") + "]";
Run Code Online (Sandbox Code Playgroud)

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

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

如果这仍然不起作用,那么您可能需要使用流式方法,尽管您可以将数组分割成多个部分并存储为多个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
}
Run Code Online (Sandbox Code Playgroud)

一种流处理方法(新的,目前仅在 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();
Run Code Online (Sandbox Code Playgroud)


Usm*_*aja 6

我发现 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");
    }
);
Run Code Online (Sandbox Code Playgroud)

从这里获取示例代码。