【问题标题】:What is the best way to keep a file open to read/write?保持文件打开以进行读/写的最佳方法是什么?
【发布时间】:2020-01-24 16:31:51
【问题描述】:

我有一个本地 JSON 文件,我打算从 NodeJS 电子应用程序中读取/写入。我不确定,但我相信我应该使用 FileHandle 来避免多次打开和关闭操作,而不是使用 readFile() 和 writeFile()。

所以我试图从 fs.promises.open() 中获取 FileHandle,但问题似乎是我无法从现有文件中获取 FileHandle 而不将其截断并将其清除为 0。

const { resolve } = require('path');
const fsPromises = require('fs').promises;

function init() {
  // Save table name
  this.path = resolve(__dirname, '..', 'data', `test.json`);

  // Create/Open the json file
  fsPromises
    .open(this.path, 'wx+')
    .then(fileHandle => {
      // Grab file handle if the file don't exists 
      // because of the flag 'wx+'
      this.fh = fileHandle;
    })
    .catch(err => {
      if (err.code === 'EEXIST') {
        // File exists
      }

    });
}

我做错了吗?有更好的方法吗?


链接:
https://nodejs.org/api/fs.html#fs_fspromises_open_path_flags_mode
https://nodejs.org/api/fs.html#fs_file_system_flags

【问题讨论】:

  • 你到底想完成什么?你不能很容易地修改 JSON,因为它是一种文本格式,所以如果有任何长度发生变化,你必须在之后重写所有内容。而且,JSON 不是一种可以轻松附加更多数据的格式。而且,在阅读方面,您也不能只阅读 JSON 的一部分。那么,你最终真正想要完成的是什么?你只是偶尔重写整个 JSON 吗?
  • 如果您想定期将新的 JSON 重写到整个文件,只需在需要重写文件时调用 fs.writeFile()。尝试在两者之间保持文件打开,没有任何理由使事情复杂化。
  • 仅供参考,如果文件已经存在,使用 x 标志可确保失败。所以,不知道你为什么要使用那个标志?
  • 我正在尝试保存应用程序的用户首选项。我明白你在说什么,作为一个 JSON 文件,我必须始终读取、解析、更改、将它们重新写入整个文件。如果只是顺序数据,我可以将数据附加到文件末尾。
  • @jfriend00 抱歉,r 标志是错误的

标签: javascript node.js io fs


【解决方案1】:

因为 JSON 是一种必须一次读取或写入的文本格式,并且不能轻易修改或添加到适当的位置,所以您将不得不读取整个文件或一次写入整个文件.

因此,您最简单的选择是只使用fs.promises.readFile()fs.promises.writeFile() 并让库打开文件、读/写并关闭文件。在现代操作系统中打开和关闭文件利用了磁盘缓存,因此如果您重新打开不久前刚刚打开的文件,这不会是一个缓慢的操作。此外,由于 nodejs 在 libuv 的辅助线程中执行这些操作,因此它也不会阻塞 nodejs 的主线程,因此它通常不会对您的服务器造成性能问题。

如果您真的想打开文件一次并保持打开状态,您可以使用r+ 标志打开它以进行读取和写入,如下所示:

const fileHandle = await fsPromises.open(this.path, 'r+');

读取整个文件会很简单,因为新的 fileHandle 对象有一个.readFile() 方法。

 const text = await fileHandle.readFile({encoding 'utf8'});

要从打开的文件句柄写入整个文件,您必须截断文件,然后写入字节,然后刷新写入缓冲区以确保数据的最后一位到达磁盘并且不在缓冲区。

await fileHandle.truncate(0);                         // clear previous contents
let {bytesWritten} = await fileHandle.write(mybuffer, 0, someLength, 0);   // write new data
assert(bytesWritten === someLength);
await fileHandle.sync();                              // flush buffering to disk

【讨论】:

    猜你喜欢
    • 2010-09-24
    • 2013-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多