简体   繁体   中英

fs.promises.writeFile resolves before it finishes writing the file

I am probably missing something obvious with this, but I have spent several days looking for solutions to this issue and have not found any.

I have a function that takes in an object, turns it into a string, and then uses the node File System to save it. It is supposed to wait for the file to finish writing before it returns, however, for whatever reason it does not.

Instead, the function begins writing the file and calls the .then () and continues before the file has been written. The file does finish writing, but it only happens after the promise has already been resolved, and thus, after the function has already continued.

I'm using node.js and it's native fs.promises api which is what a lot of similar questions suggest (although many of them are from when fs.promises was still experimental)

The code:

const fs = require(`fs`);
const fsPromises = fs.promises;
const path = require (`path`);

var server = `test`;
const settings = {
  "name": "srvr.name",
  "serverId": "srvr.id",
  "ownerId": "srvr.ownerId",
  "prefix": "!",
  "roles":
  {
    "bot":
    {
      "id": "srvr.me.roles.highest.id",
      "name": "srvr.me.roles.highest.name"
    }
  }
};

saveSettings (server, settings);

Function:

async function saveSettings (server, settings) {

  const newSettings = await JSON.stringify (settings, null, `\t`);

  await fsPromises.writeFile (path.join (__dirname, `${server}.json`), newSettings)
  .then (console.log (`File Saved`));

  await console.log (fs.readFileSync (path.join (__dirname, `${server}.json`)));

  return console.log (`Settings Saved`);
}

Expected Result:

File Saved
{
  "name": "srvr.name",
  "serverId": "srvr.id",
  "ownerId": "srvr.ownerId",
  "prefix": "!",
  "roles":
  {
    "bot":
    {
      "id": "srvr.me.roles.highest.id",
      "name": "srvr.me.roles.highest.name"
    }
  }
}
Settings Saved

Actual Result:

File Saved
<Buffer 7b 0a 09 22 6e 61 6d 65 22 3a 20 22 73 72 76 72 2e 6e 61 6d 65 22 2c 0a 09 22 73 65 72 76 65 72 49 64 22 3a 20 22 73 72 76 72 2e 69 64 22 2c 0a 09 22 ... 150 more bytes>
Settings Saved

As you can see, the file is still being written when the function attempts to read it.

From my understanding, fs.promises.writeFile returns a promise that will be resolved when the file has finished writing, but it doesn't appear to be doing so.

I started using fs.writeFile, however discovered that it did not return a promise and therefore await would not work with it. I have also tried fs.writeFileSync, just in case that might have worked, but as expected, it did not.

I do not know if the object is too large, and so the file takes too long to write, but as far as I can tell, that shouldn't be an issue, as the promise should not resolve until the file has been written, regardless of how long it takes.

I know I am probably missing something very obvious here, whether I'm missing the way writeFile works, or am using the wrong function altogether, but I do not know what.

In case it is useful, this function is for use in a Discord bot using Discord.js

Thanks in advance

await console.log (fs.readFileSync (path.join (__dirname, `${server}.json`)));

This isn't how you do this.

You want to

console.log(await fsPromises.readFileSync (path.join (__dirname, `${server}.json`)));

The promise is returned by fsPromises.readFileSync, not console.log.

The answer was noted in the comments by user Phix, but for good measure, the issue isn't that the file was still being written, but that by default readFile returns a buffer , not a string. The solution is to pass the encoding option to readFile/readFileSync, which probably should be utf-8 . For good measure, you should also include that encoding when you write the file.

When writing(async) file is in progress, it tries to read(sync) the file. So in your case there is no need to write file async. Also you use await on sync function calls unnecessarily. I would write the function as below via using both sync write and read.

function saveSettings (server, settings) {

  const newSettings = JSON.stringify (settings, null, `\t`);

  const settingsPath = path.join(__dirname, `${server}.json`);
  fs.writeFileSync(settingsPath, newSettings); // writes settings sync

  console.log(fs.readFileSync(settingsPath)); //read settings sync and print

  console.log (`Settings Saved`);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM