【问题标题】:How to read file with async/await properly?如何正确读取带有 async/await 的文件?
【发布时间】:2018-04-02 17:05:45
【问题描述】:

我无法弄清楚async/await 的工作原理。我有点理解,但我不能让它工作。

function loadMonoCounter() {
    fs.readFileSync("monolitic.txt", "binary", async function(err, data) {
       return await new Buffer( data);
  });
}

module.exports.read = function() {
  console.log(loadMonoCounter());
};

我知道,我可以使用readFileSync,但如果我这样做了,我知道我永远不会理解async/await,我会直接把这个问题埋没。

目标:调用loadMonoCounter()并返回一个文件的内容。

每次调用incrementMonoCounter()(每次页面加载)时,该文件都会递增。该文件包含二进制缓冲区的转储,并存储在 SSD 上。

无论我做什么,我都会在控制台中收到错误或undefined

【问题讨论】:

标签: node.js asynchronous readfile


【解决方案1】:

由于 Node v11.0.0 fs 承诺在没有 promisify 的情况下本机可用:

const fs = require('fs').promises;
async function loadMonoCounter() {
    const data = await fs.readFile("monolitic.txt", "binary");
    return new Buffer(data);
}

【讨论】:

  • 截至 2019 年 10 月 21 日,v12 是有效的 LTS 版本
  • import { promises as fs } from "fs"; 如果你想使用导入语法。
  • 关于这种方法的注释,虽然它很干净,但它也不会在fs.promises api 之外导入fs 的其他有用功能。将fsfs.promises 分开导入可能很重要。
  • 我得到了一个奇怪的响应:Buffer(18524) [60, 115, 99, 114, 105, 112, 116, 32, 116, 110, 116, 45, 108, 105 , 98, 62, 13, 10, 32, 32, 32, 32, 47, 42, 42, 13, 10, 32, 32, 32, 32, 32, 42, 32, 67, 111, 112, 121, 114 ,, ...] 会是什么?
  • 一旦你有了 Buffer,你可以使用 Buffer 的方法 toString()bufferData.toString() 将其转换为字符串 - 请参阅 docs for Buffer
【解决方案2】:

要使用await/async,您需要返回承诺的方法。如果没有像 promisify 这样的包装器,核心 API 函数就不会这样做:

const fs = require('fs');
const util = require('util');

// Convert fs.readFile into Promise version of same    
const readFile = util.promisify(fs.readFile);

function getStuff() {
  return readFile('test');
}

// Can't use `await` outside of an async function so you need to chain
// with then()
getStuff().then(data => {
  console.log(data);
})

注意,readFileSync 不接受回调,它返回数据或抛出异常。你没有得到你想要的值,因为你提供的函数被忽略并且你没有捕获实际的返回值。

【讨论】:

  • 核心 API 早于现代 Promise 规范和 async/await 的采用,因此这是一个必要的步骤。好消息是promisify 通常可以让它工作起来不会乱七八糟。
  • 这处理了无法正常利用 FS 的 async-await 的混乱。这次真是万分感谢!你救了我一吨!没有一个答案能像你的那样真正解决这个问题。
  • 另外 await 有点多余,因为它可以被推断出来。仅当您确实想在示例中明确地等待时,您才能执行const file = await readFile...; return file;
  • @tadman 我们还需要在最新版本的节点中承诺吗?
  • @shijin 直到 Node 核心 API 切换到 Promise,这在此时不太可能,然后是的。不过,有 NPM 包装器可以为你做这件事。
【解决方案3】:

这是@Joel 答案的 TypeScript 版本。在Node 11.0之后可以使用:

import { promises as fs } from 'fs';

async function loadMonoCounter() {
    const data = await fs.readFile('monolitic.txt', 'binary');
    return Buffer.from(data);
}

【讨论】:

    【解决方案4】:

    您可以使用如下的 promise 轻松包装 readFile 命令:

    async function readFile(path) {
        return new Promise((resolve, reject) => {
          fs.readFile(path, 'utf8', function (err, data) {
            if (err) {
              reject(err);
            }
            resolve(data);
          });
        });
      }
    

    然后使用:

    await readFile("path/to/file");
    

    【讨论】:

    • async 函数内部没有使用 await 吗?
    • @VikasBhat 是的,上面的 await 行将在另一个异步函数中使用,因为规范要求这样做。
    • 您在if (err) 路径上缺少返回。
    • 启动时一定要写异步函数吗?
    【解决方案5】:

    您可以使用自 Node v11.0.0 起本机可用的 fs.promises

    import fs from 'fs';
    
    const readFile = async filePath => {
      try {
        const data = await fs.promises.readFile(filePath, 'utf8')
        return data
      }
      catch(err) {
        console.log(err)
      }
    }
    

    【讨论】:

    • 如果你只想使用 Promise,你可以这样做 const fs = require('fs').promises
    • @nathanfranke 这没有使用导入
    • 对于导入你可以做import { promises } from "fs"
    【解决方案6】:

    为了保持简洁并保留fs的所有功能:

    const fs = require('fs');
    const fsPromises = fs.promises;
    
    async function loadMonoCounter() {
        const data = await fsPromises.readFile('monolitic.txt', 'binary');
        return new Buffer(data);
    }
    

    分别导入fsfs.promises 将提供对整个fs API 的访问权限,同时还保持其更具可读性...这样就可以轻松完成下一个示例。

    // the 'next example'
    fsPromises.access('monolitic.txt', fs.constants.R_OK | fs.constants.W_OK)
        .then(() => console.log('can access'))
        .catch(() => console.error('cannot access'));
    

    【讨论】:

    • DeprecationWarning: Buffer() 由于安全性和可用性问题而被弃用。请改用 Buffer.alloc()、Buffer.allocUnsafe() 或 Buffer.from() 方法。
    【解决方案7】:

    从节点 v14.0.0

    const {readFile} = require('fs/promises');
    
    const myFunction = async()=>{
        const result = await readFile('monolitic.txt','binary')
        console.log(result)
    }
    
    myFunction()
    

    【讨论】:

    • 酷!谢谢! fs/promises 看起来不错
    【解决方案8】:

    有一个fs.readFileSync( path, options )方法,是同步的。

    【讨论】:

      【解决方案9】:
      const fs = require("fs");
      const util = require("util");
      const readFile = util.promisify(fs.readFile);
      const getContent = async () => {
      let my_content;
      try {
        const { toJSON } = await readFile("credentials.json");
        my_content = toJSON();
        console.log(my_content);
      } catch (e) {
        console.log("Error loading client secret file:", e);
       }
      };
      

      【讨论】:

        【解决方案10】:

        我使用Promise 读取文件。对我来说是正确的:

        const fs = require('fs')
        
        //function which return Promise
        const read = (path, type) => new Promise((resolve, reject) => {
          fs.readFile(path, type, (err, file) => {
            if (err) reject(err)
            resolve(file)
          })
        })
        
        //example how call this function
        read('file.txt', 'utf8')
            .then((file) => console.log('your file is '+file))
            .catch((err) => console.log('error reading file '+err))
        
        //another example how call function inside async
        async function func() {
          let file = await read('file.txt', 'utf8')
          console.log('your file is '+file)
        }
        

        【讨论】:

          【解决方案11】:

          您可以在下面找到我的方法: 首先,我需要 fs 作为 fsBase,然后我将“promises”放入 fs 变量中。

          const fsBase = require('fs');
          const fs = fsBase.promises
          
          const fn = async () => {
              const data = await fs.readFile('example.txt', 'utf8');
              console.log(data);
          };
          
          fn();
          

          【讨论】:

          • 这是@NonCreature0714 的答案的副本
          【解决方案12】:

          看这个例子 https://www.geeksforgeeks.org/node-js-fs-readfile-method/

          // Include fs module
          var fs = require('fs');
            
          // Use fs.readFile() method to read the file
          fs.readFile('demo.txt', (err, data) => {
            console.log(data);
          })

          【讨论】:

            猜你喜欢
            • 2018-05-18
            • 2019-05-30
            • 2020-08-23
            • 2018-09-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多