【问题标题】:Append JSON to a file using node streams使用节点流将 JSON 附加到文件
【发布时间】:2019-06-29 16:08:27
【问题描述】:

根据我读过的here,我正在使用fs.createWriteStream 将一些JSON 写入文件。我正在处理大约 50 个块的数据。所以在脚本的开头,我打开了我的流,然后使用一个函数将它以及一些 JSON 传递进来,这对于编写来说非常有效。

const myStream = fs.createWriteStream(
  path.join(RESULTS_DIR, `my-file.json`),
  {
    flags: 'a'
  }
)


function appendJsonToFile(stream, jsonToAppend) {
  return new Promise((resolve, reject) => {
    try {
      stream.write(JSON.stringify(jsonToAppend, null, 2)
      resolve('STREAM_WRITE_SUCCESS')
    } catch (streamError) {
      reject('STREAM_WRITE_FAILURE', streamError)
    }
  })
}

appendJsonToFile(myStream, someJson)

但是,因为要写入的每条数据都是一个对象数组,所以我最终在文件中获得的结构将如下所示:

[
    {
        "data": "test data 1",
    },
        {
        "data": "test data 2",
    }
][
    {
        "data": "test data 3",
    },
        {
        "data": "test data 4",
    }
]

如何附加这些数据,以便结果是格式正确的 JSON,而不仅仅是一系列数组?

【问题讨论】:

    标签: javascript node.js json stream node-streams


    【解决方案1】:

    如果文件始终如您所说的那样格式化,您需要做的三件事是:

    1. 找出文件的当前长度并减去 2 个字符(\n],因为末尾没有换行符),
    2. 删除您要保存的 JSON 的第一个字符,
    3. 使用r+ 模式和start 保存文件
    4. 每次保存后结束直播。

    这是createWriteStream options的链接。

    现在另一件事是第 4 点使这变得相当低效,并且质疑是否应该在此处使用流式传输的整个想法。我认为这确实有意义,但这里的问题是您是否需要在写入之间读取文件 - 如果不需要,那么您应该在中间使用 transform stream 并在文件之间添加刷新,并且在所有工作完成之后( beforeExit) 您只需结束流即可。

    您可以按定义执行此操作,但我是一个名为 scramjet 的框架的作者,它使这些案例变得更加容易:

    const myStream = new scramjet.DataStream();
    
    const file = path.join(RESULTS_DIR, `my-file.json`)
    const start = fs.statSync(file).size - 2;
    
    myStream
        .flatten()
        .toJSONArray()
        .shift(1)
        .pipe(fs.createWriteStream(
            file,
            {flags: 'r+', start}
        ));
    
    function appendJsonToFile(stream, jsonToAppend) {
        return new Promise((resolve, reject) => {
            try {
                stream.write(jsonToAppend)
                resolve('STREAM_WRITE_SUCCESS')
            } catch (streamError) {
                reject('STREAM_WRITE_FAILURE', streamError)
            }
        })
    }
    
    appendJsonToFile(myStream, someJson)
    
    process.on('beforeExit', myStream.end());
    

    您可以像上面那样使用它,但是如果您更喜欢使用普通节点流来处理它,这应该会推动您朝着正确的方向前进。

    【讨论】:

    • 这真是太棒了!你能展示一个使用变换/刷新的例子吗?
    【解决方案2】:

    我将使用 Error 和 FILE NOT FOUND 处理程序解析代码。源自 Michał Karpacki 的解决方案。

    const path = require('path');
    const fs = require('fs');
    
    const getFolderPath = () => __dirname || process.cwd();
    const getFilePath = (fileName) => path.join(getFolderPath(), `${fileName}`);
    
    /**
     * @param {string} fileName - Included File Name & its Extension
     * @param {Array<*>} arrayData
     * @return {Promise<*>}
     */
    const writeFileAsync = async (fileName, arrayData) => {
        const filePath = getFilePath(fileName);
    
        return new Promise((resolve, reject) => {
            try {
                const _WritableStream = fs.createWriteStream(filePath, {flags: 'r+', start: fs.statSync(filePath).size - 2});
                _WritableStream.write(JSON.stringify(arrayData, null, 2).replace(/\[/, ','), (streamError) => {
                    return reject(['STREAM_WRITE_FAILURE', streamError]);
                });
                return resolve('STREAM_WRITE_SUCCESS');
            } catch (streamError) {
                /** ERROR NOT FOUND SUCH FILE OR DIRECTORY !*/
                if (streamError.code === 'ENOENT') {
                    fs.mkdirSync(getFolderPath(), {recursive: true});
                    return resolve(fs.writeFileSync(filePath, JSON.stringify(
                        Array.from({...arrayData, length: arrayData.length}), null, 2
                    )));
                }
                /** ERROR OUT OF BOUND TO FILE SIZE RANGE - INVALID START POSITION FOR WRITE STREAM !*/
                if (streamError instanceof RangeError) {
                    console.error(`> [ERR_OUT_OF_RANGE] =>`, streamError);
                    const _WritableStream = fs.createWriteStream(filePath, {flags: 'r+'});
                    return resolve(_WritableStream.write(JSON.stringify(arrayData, null, 2), (streamError) => {
                        return reject(['STREAM_WRITE_FAILURE', streamError]);
                    }));
                }
                return reject(['STREAM_WRITE_FAILURE', streamError]);
            }
        });
    };
    
    (() => writeFileAsync('test1.json',
        [{
            key: "value 1"
        }, {
            key: "value 2"
        }]
    ))();
    
    /* Output after 1st time run =>
    [
      {
        "key": "value 1"
      },
      {
        "key": "value 2"
      }
    ]
    */
    /* Output after 2nd time run => 
    [
      {
        "key": "value 1"
      },
      {
        "key": "value 2"
      },
      {
        "key": "value 1"
      },
      {
        "key": "value 2"
      }
    ]
    */
    

    【讨论】:

    • 请解释你的答案,以便下一个用户知道为什么这个解决方案对你有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多