从 fs.readFile 获取数据

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

日志 undefined,为什么?

721643 次浏览

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

这里实际上有一个同步函数:

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)

如前所述,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仍然是空的。Node尚未检索到文件的内容。

这可以通过将console.log(content)移动到回调函数内部,位于content = data;之后来解决。这样,当节点读取文件时,以及content获得一个值之后,您将看到日志。

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

同步调用文件

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

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

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

你可以读取文件

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);
}
});
};
var content;
fs.readFile('./Index.html', function read(err, data) {
if (err) {
throw err;
}
content = data;
});
console.log(content);

这只是因为节点是异步的,它不会等待读取函数,一旦程序启动,它将控制台的值为未定义,这实际上是真的,因为没有赋值给内容变量。 我们可以使用承诺、生成器等来处理。 我们可以这样使用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.
})

粗略地说,你在处理本质上是异步的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);
});
这是异步的。这很难适应,但事实就是这样。 同样,这是对async的粗略但快速的解释
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!");
});
});
}

使用内置的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 content = fs.readFileSync('./Index.html', 'utf8');
console.log(content);

下面的函数将适用于async wrap或promise then

const readFileAsync =  async (path) => fs.readFileSync(path, 'utf8');
var path = "index.html"


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

使用简单的readFileSync适合我。

我喜欢使用fs-extra,因为所有函数都是约定的,开箱即用,所以你可以使用await。所以你的代码可以是这样的:

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