从fs.readFile获取数据


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

日志undefined,为什么?


1
fs.readFileSync也具有很酷的功能,即使文件采用Unicode utf8格式,也可以读取文件。
Praneeth

NB fs.readFile也可以做到这一点^见下面我的答案
Dominic

Answers:


347

为了详细说明@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
});

2
同步I / O占有一席之地-如果您使用的是小型构建系统或工具,那很好。在较大的系统或服务器应用程序上,最佳实践是避免这种情况。
RobW

27
并非所有内容都是Web服务器。在服务器开始接收请求之前,使用同步版本的方法进行一次调用并不可怕。使用Node的任何人都应该在使用它之前真正了解其原因。绝对是在骚动博客之前。
Erik Reppen'3


7
您必须'utf8'在文件名后面添加一个附加参数,否则它将返回一个缓冲区。参见:stackoverflow.com/questions/9168737/…–
DollarAkshay

252

实际上有一个同步功能:

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的同步版本中返回的缓冲区有什么用途?如果我同步读取文件并且未通过任何编码,它将打印缓冲区,我该如何使用它?谢谢。
–codingbbq

12
我最近有这个经验。假设我们的缓冲区是dataif (Buffer.isBuffer( data){ result = data.toString('utf8'); }现在,我们已将缓冲区转换为可读文本。这对于读取纯文本文件或针对格式类型测试文件很有用。我可以尝试/捕获以查看它是否为JSON文件。但仅在将缓冲区转换为文本之后。在此处查看更多信息:nodejs.org/api/buffer.html
Logan

据我所知,缓冲区是八位位组流,非常适合“逐段”发送数据。您一定已经看到缓冲区类似于AF 42 F1。对于客户端-服务器-客户端通信非常实用。
Logan

113
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)
})

6
非常感谢,如果我有15分,我会投票赞成你的答案:)
karaxuna 2012年

嗨,在代码的第一行中function readContent(callback),是callback保留字?我的意思是,这是为您的自定义函数实现回调的标准方法吗?我刚刚开始学习节点。
阿玛尔安东尼

3
嗨,阿玛 回调只是传递给他的函数的参数,它可以是eventc任何您喜欢的名称-它不是Javascript中的保留字,并且我想同样地扩展到Node.js。
RealDeal_EE'13年

readContent(function (err, content)使用函数作为参数时,出现语法错误。
monsto

66

在ES7中使用Promises

与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 ) }
};

6
这是未来,每个人都应该高度反对:)谢谢
PirateApp '16

2
看起来很有趣。一种错字:“ console.error(catch)”应该是“ console.error(err)”(我认为)。
philwalk

2
如果您不想添加额外的程序包,请尝试以下@doctorlee的解决方案
rahuljain1311 '18

18
var data = fs.readFileSync('tmp/reltioconfig.json','utf8');

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


2
您需要的代码块一个空行,以便为这个漂亮的印刷一命呜呼
royhowie

简报和最好的!
钻石

12

这条线会工作,

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

1
7年过去了:) fs.readFileSync是同步方法,因此不需要await那里。当您要使用类似于同步代码的语法编写异步代码时,等待对诺言很有用(nodejs.org/api/fs.html#fs_fs_promises_api)。
karaxuna

@karaxuna,是的。删除。我今天刚刚遇到这种情况,并使用上面的代码解决了。
Aravin

1
这是最简单的答案。如果您不需要异步,那么为什么您会在世界范围内与异步版本,回调,异步/等待等一起使用呢?这是要走的路。
鸭子大师

8
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!");
      });
    });
  }

5
请不要只在您的答案中添加代码...说明为什么它与众不同以及它如何解决问题。
Studocwho

@doctorlee这实际上对我有用,没有任何外部库。肯定需要解释。
Ashutosh Chamoli

7

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

//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获得


7

如前所述,fs.readFile是一个异步动作。这意味着,当您告诉节点读取文件时,您需要考虑这将花费一些时间,与此同时,节点继续运行以下代码。您的情况是: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获得值后,您将看到日志。


6

使用内置的Promisify库(节点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换行。
rab

1
这样做的重点是不使用同步版本,您应该在调用它时处理错误
Dominic

4
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());
});

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

这仅仅是因为节点是异步的,并且它不会等待读取功能,并且程序一旦启动,它将把值定义为undefined,这实际上是正确的,因为没有将值分配给content变量。为了处理,我们可以使用promise,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.
})

2

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

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

1

您可以通过以下方式读取文件

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

1

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

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

您的代码:

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

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

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

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

这是异步的。很难适应,但事实就是如此。同样,这是对什么是异步的粗略但快速的解释。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.