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

日志undefined,为什么?

4

17 回答 17

381

详细说明@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
});
于 2012-04-07T22:25:00.973 回答
292

实际上有一个同步功能:

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)
于 2012-12-29T04:15:49.920 回答
124
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)
})
于 2012-04-07T22:36:25.630 回答
72

在 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 ) }
};
于 2016-05-30T02:28:35.153 回答
22

这条线会工作,

const content = fs.readFileSync('./Index.html', 'utf8');
console.log(content);
于 2019-01-08T12:52:33.693 回答
21
var data = fs.readFileSync('tmp/reltioconfig.json','utf8');

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

于 2015-06-01T07:31:41.730 回答
10
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!");
      });
    });
  }
于 2018-08-23T21:25:42.953 回答
9

使用内置的 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);
  }
}
于 2018-09-19T18:37:15.793 回答
8

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

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

看看我写的评论:

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获取值后,您将看到日志。

于 2014-04-11T21:23:49.490 回答
8

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

//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);

节点作弊可在read_file 获得

于 2016-04-16T07:50:33.097 回答
5
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());
});
于 2016-10-23T07:28:03.070 回答
5
var content;
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
});
console.log(content);

这只是因为节点是异步的,它不会等待读取函数,并且一旦程序启动它就会将值控制台为未定义,这实际上是正确的,因为没有为内容变量分配值。为了处理我们可以使用 Promise、生成器等。我们可以通过这种方式使用 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.
})
于 2018-08-02T09:49:48.910 回答
4

以下是适用于async包装或承诺then链的功能

const readFileAsync =  async (path) => fs.readFileSync(path, 'utf8');
于 2019-09-16T07:52:10.553 回答
4
var path = "index.html"

const readFileAsync = fs.readFileSync(path, 'utf8');
// console.log(readFileAsync)

为我使用简单readFileSync的作品。

于 2021-02-23T08:17:13.687 回答
2

你可以通过阅读文件

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);
    }
  });
};
于 2018-07-17T13:35:06.500 回答
2

粗略地说,您正在处理本质上是异步的 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);
});

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

于 2018-08-17T07:51:22.893 回答
1

我喜欢使用fs-extra,因为所有功能都是承诺的,开箱即用,因此您可以使用await. 因此,您的代码可能如下所示:

(async () => {
   try {
      const content = await fs.readFile('./Index.html');
      console.log(content);
   } catch (err) {
      console.error(err);
   }
})();
于 2021-07-20T00:42:14.040 回答