【问题标题】:Get data from fs.readFile从 fs.readFile 获取数据
【发布时间】:2012-04-20 23:25:59
【问题描述】:
var content;
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
});
console.log(content);

记录undefined,为什么?

【问题讨论】:

  • fs.readFileSync 也有很酷的功能来读取文件,即使它是 unicode utf8 格式。
  • 注: fs.readFile 也可以做到这一点^见下面我的回答

标签: javascript node.js


【解决方案1】:

详细说明@Raynos 所说的,您定义的函数是异步回调。它不会立即执行,而是在文件加载完成时执行。当您调用 readFile 时,立即返回控制并执行下一行代码。所以当你调用console.log的时候,你的回调还没有被调用,这个内容还没有被设置。欢迎使用异步编程。

示例方法

const fs = require('fs');
// First I want to read the file
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    const content = data;

    // Invoke the next step here however you like
    console.log(content);   // Put all of the code here (not the best solution)
    processFile(content);   // Or put the next step in a function and invoke it
});

function processFile(content) {
    console.log(content);
}

或者更好的是,正如 Raynos 示例所示,将您的调用包装在一个函数中并传入您自己的回调。 (显然这是更好的做法)我认为养成将异步调用包装在接受回调的函数中的习惯将为您节省很多麻烦和混乱的代码。

function doSomething (callback) {
    // any async callback invokes callback with response
}

doSomething (function doSomethingAfter(err, result) {
    // process the async result
});

【讨论】:

  • 同步 I/O 有它的位置——如果你正在做一个小型的构建系统或工具,这很好。在较大的系统或服务器应用程序上,最佳做法是避免它。
  • 并非一切都是 Web 服务器。在服务器开始接受请求之前,使用同步版本的方法进行一次性调用并没有什么可怕的。任何使用 Node 的人都应该在使用它之前真正理解为什么。绝对是在写博客之前。
  • 您必须在文件名之后包含'utf8' 作为附加参数,否则它只会返回一个缓冲区。请参阅:stackoverflow.com/questions/9168737/…
【解决方案2】:

实际上有一个同步函数:

http://nodejs.org/api/fs.html#fs_fs_readfilesync_filename_encoding

异步

fs.readFile(filename, [encoding], [callback])

异步读取文件的全部内容。示例:

fs.readFile('/etc/passwd', function (err, data) {
  if (err) throw err;
  console.log(data);
});

回调传递了两个参数(err, data),其中 data 是文件的内容。

如果没有指定编码,则返回原始缓冲区。


同步

fs.readFileSync(filename, [encoding])

fs.readFile 的同步版本。返回名为 filename 的文件的内容。

如果指定了编码,则此函数返回一个字符串。否则它返回一个缓冲区。

var text = fs.readFileSync('test.md','utf8')
console.log (text)

【讨论】:

  • 快速问题,在 readFile 的同步版本中返回的缓冲区有什么用?如果我同步读取文件并且不传递任何编码,它会打印缓冲区,我该如何使用它?谢谢。
  • 我最近有过这方面的经验。假设我们的缓冲区是dataif (Buffer.isBuffer( data){ result = data.toString('utf8'); } 现在我们已经将缓冲区转换为可读文本。这对于读取纯文本文件或针对格式类型测试文件很有用。例如,我可以尝试/捕获以查看它是否是 JSON 文件;但只有在缓冲区转换为文本之后。在这里查看更多信息:nodejs.org/api/buffer.html
  • 据我所知,缓冲区是八位字节流,适合“逐段”发送数据。您一定已经看到缓冲区类似于AF 42 F1。对于客户端-服务器-客户端通信非常实用。
【解决方案3】:
function readContent(callback) {
    fs.readFile("./Index.html", function (err, content) {
        if (err) return callback(err)
        callback(null, content)
    })
}

readContent(function (err, content) {
    console.log(content)
})

【讨论】:

  • 您好,在您的代码的第一行function readContent(callback)callback 是保留字吗?我的意思是,这是为您的自定义函数实现回调的标准方法吗?我刚开始学习node。
  • 嗨,阿迈勒。回调只是传递给他的函数的参数,它可以是 eventc 或您喜欢的任何名称 - 它不是 Javascript 中的保留字,我假设同样扩展到 Node.js。
  • readContent(function (err, content) 将函数用作参数时出现语法错误。
【解决方案4】:

在 ES7 中使用 Promise

与 mz/fs 异步使用

mz 模块提供了核心节点库的承诺版本。使用它们很简单。首先安装库...

npm install mz

那么……

const fs = require('mz/fs');
fs.readFile('./Index.html').then(contents => console.log(contents))
  .catch(err => console.error(err));

您也可以将它们写在异步函数中:

async function myReadfile () {
  try {
    const file = await fs.readFile('./Index.html');
  }
  catch (err) { console.error( err ) }
};

【讨论】:

  • 看起来很有趣。一个错字:'console.error(catch)' 应该是 'console.error(err)' 我猜)。
  • 如果您不想添加额外的包,请尝试以下@doctorlee 的解决方案
【解决方案5】:

这条线可以用,

const content = fs.readFileSync('./Index.html', 'utf8');
console.log(content);

【讨论】:

  • 7 年过去了 :) fs.readFileSync 是同步方法,所以那里不需要 await。当您想编写语法类似于同步代码的异步代码时,Await 对 Promise (nodejs.org/api/fs.html#fs_fs_promises_api) 很有用。
  • @karaxuna,是的。删除。我今天刚遇到这个案例,我用上面的代码解决了。
  • 这是最简单的答案。如果您不需要异步,那您到底为什么要与异步版本、回调、异步/等待等混合使用?这是要走的路。
【解决方案6】:
var data = fs.readFileSync('tmp/reltioconfig.json','utf8');

使用它来同步调用文件, 无需将其显示输出编码为缓冲区。

【讨论】:

  • 您需要在代码块之前有一个空行,以便进行漂亮的打印。
【解决方案7】:
const fs = require('fs')
function readDemo1(file1) {
    return new Promise(function (resolve, reject) {
        fs.readFile(file1, 'utf8', function (err, dataDemo1) {
            if (err)
                reject(err);
            else
                resolve(dataDemo1);
        });
    });
}
async function copyFile() {

    try {
        let dataDemo1 = await readDemo1('url')
        dataDemo1 += '\n' +  await readDemo1('url')

        await writeDemo2(dataDemo1)
        console.log(dataDemo1)
    } catch (error) {
        console.error(error);
    }
}
copyFile();

function writeDemo2(dataDemo1) {
    return new Promise(function(resolve, reject) {
      fs.writeFile('text.txt', dataDemo1, 'utf8', function(err) {
        if (err)
          reject(err);
        else
          resolve("Promise Success!");
      });
    });
  }

【讨论】:

  • 请不要只在答案中添加代码...解释为什么它不同以及它如何解决问题。
  • @doctorlee 这实际上对我有用,没有任何外部库。肯定需要解释。
【解决方案8】:

使用内置的 promisify 库(Node 8+)使这些旧的回调函数更加优雅。

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

const readFile = util.promisify(fs.readFile);

async function doStuff() {
  try {
    const content = await readFile(filePath, 'utf8');
    console.log(content);
  } catch (e) {
    console.error(e);
  }
}

【讨论】:

  • 可以单行const doStuff = async (filePath) => fs.readFileSync(filePath, 'utf8');,不需要util.promisify wrap。
  • 不使用同步版本是重点,你应该在调用它时处理错误
【解决方案9】:

同步和异步文件读取方式:

//fs module to read file in sync and async way

var fs = require('fs'),
    filePath = './sample_files/sample_css.css';

// this for async way
/*fs.readFile(filePath, 'utf8', function (err, data) {
    if (err) throw err;
    console.log(data);
});*/

//this is sync way
var css = fs.readFileSync(filePath, 'utf8');
console.log(css);

Node Cheat 可在read_file 获得。

【讨论】:

    【解决方案10】:

    如前所述,fs.readFile 是一个异步操作。意思是当你告诉node读取一个文件的时候,需要考虑到会需要一些时间,同时node会继续运行下面的代码。在您的情况下,它是:console.log(content);

    这就像发送您的部分代码进行长途旅行(例如读取一个大文件)。

    看看我写的cmets:

    var content;
    
    // node, go fetch this file. when you come back, please run this "read" callback function
    fs.readFile('./Index.html', function read(err, data) {
        if (err) {
            throw err;
        }
        content = data;
    });
    
    // in the meantime, please continue and run this console.log
    console.log(content);
    

    这就是为什么content 在您登录时仍然为空。节点尚未检索到文件的内容。

    这可以通过在回调函数中移动console.log(content) 来解决,就在content = data; 之后。这样,当节点完成读取文件并在content 获取值之后,您将看到日志。

    【讨论】:

      【解决方案11】:
      var fs = require('fs');
      var path = (process.cwd()+"\\text.txt");
      
      fs.readFile(path , function(err,data)
      {
          if(err)
              console.log(err)
          else
              console.log(data.toString());
      });
      

      【讨论】:

        【解决方案12】:
        var content;
        fs.readFile('./Index.html', function read(err, data) {
            if (err) {
                throw err;
            }
            content = data;
        });
        console.log(content);
        

        这只是因为节点是异步的,它不会等待读取函数,并且一旦程序启动它就会将值控制台为未定义,这实际上是正确的,因为没有为内容变量分配值。 为了处理我们可以使用 promises、generators 等。 我们可以这样使用promise。

        new Promise((resolve,reject)=>{
            fs.readFile('./index.html','utf-8',(err, data)=>{
                if (err) {
                    reject(err); // in the case of error, control flow goes to the catch block with the error occured.
                }
                else{
                    resolve(data);  // in the case of success, control flow goes to the then block with the content of the file.
                }
            });
        })
        .then((data)=>{
            console.log(data); // use your content of the file here (in this then).    
        })
        .catch((err)=>{
            throw err; //  handle error here.
        })
        

        【讨论】:

          【解决方案13】:

          以下函数适用于 async wrap 或 promise then

          const readFileAsync =  async (path) => fs.readFileSync(path, 'utf8');
          

          【讨论】:

          • 你并没有通过在它上面放置一个等待来使函数异步,它仍然会进行同步读取并返回一个立即解决的承诺
          • readFileSync 是同步功能,因此与不是 make scene 的 await 一起使用。我们应该用 util.promisify(readFile) 包裹 readFile 然后你可以使用 await 。希望对您有所帮助!
          【解决方案14】:
          var path = "index.html"
          
          const readFileAsync = fs.readFileSync(path, 'utf8');
          // console.log(readFileAsync)
          

          使用简单的readFileSync 对我有用。

          【讨论】:

            【解决方案15】:

            你可以通过阅读文件

            var readMyFile = function(path, cb) {
                  fs.readFile(path, 'utf8', function(err, content) {
                    if (err) return cb(err, null);
                    cb(null, content);
                  });
                };
            

            添加后可以写入文件,

            var createMyFile = (path, data, cb) => {
              fs.writeFile(path, data, function(err) {
                if (err) return console.error(err);
                cb();
              });
            };
            

            甚至连在一起

            var readFileAndConvertToSentence = function(path, callback) {
              readMyFile(path, function(err, content) {
                if (err) {
                  callback(err, null);
                } else {
                  var sentence = content.split('\n').join(' ');
                  callback(null, sentence);
                }
              });
            };
            

            【讨论】:

              【解决方案16】:

              粗略地说,您正在处理本质上是异步的 node.js。

              当我们谈论异步时,我们指的是在处理其他事情的同时做或处理信息或数据。不是并行的同义词,请注意。

              你的代码:

              var content;
              fs.readFile('./Index.html', function read(err, data) {
                  if (err) {
                      throw err;
                  }
                  content = data;
              });
              console.log(content);
              

              对于您的示例,它基本上首先执行 console.log 部分,因此变量“内容”未定义。

              如果您真的想要输出,请执行以下操作:

              var content;
              fs.readFile('./Index.html', function read(err, data) {
                  if (err) {
                      throw err;
                  }
                  content = data;
                  console.log(content);
              });
              

              这是异步的。这将很难习惯,但它就是这样。 同样,这是对异步是什么的粗略但快速的解释。

              【讨论】:

                【解决方案17】:

                我喜欢使用fs-extra,因为所有功能都是承诺的,开箱即用,所以你可以使用await。所以你的代码可能看起来像这样:

                (async () => {
                   try {
                      const content = await fs.readFile('./Index.html');
                      console.log(content);
                   } catch (err) {
                      console.error(err);
                   }
                })();
                

                【讨论】:

                  猜你喜欢
                  • 2023-03-23
                  • 1970-01-01
                  • 2016-05-14
                  • 1970-01-01
                  • 2020-06-13
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-02-06
                  相关资源
                  最近更新 更多