我有一个数组,说... 100000个对象。我使用map函数,在每次迭代中,我构建一个字符串并将内容写入CSV,如下所示:
entriesArray.map((entry) => {
let str = entry.id + ',' + entry.fname + ',' + entry.lname + ',' +
entry.address + ',' + entry.age + ',' + entry.sex + '\n'
writeToFile(str);
});
writeToFile函数:
const writeToFile = (str) => {
fs.appendFile(outputFileName + '.csv', str, (err) => {
if (err) throw err;
});
};
这可以按预期工作,但我担心如果有这么多异步写操作可能会导致任何数据不一致。所以我的问题是,这样安全吗?或者有更好的方法来做到这一点。
顺便说一下,MAC OS上的相同代码抛出错误错误:ENFILE:文件表溢出,打开' output.csv'。经过一番研究,我了解到这是因为OSX具有非常低的打开文件限制。有关详细信息,请参见here。
我再次希望改进我的文件写入机制也可以解决这个问题。
答案 0 :(得分:3)
你是正确的认识到这不是一种好的编码方式,因为不能保证异步写入的顺序(特别是如果写入很大并且可能需要对磁盘执行多次实际写入操作)。并且,请记住fs.appendfile()
实际上包含三个异步操作fs.open()
,fs.write()
和fs.close()
。而且,正如您所看到的,这会同时打开大量文件句柄,因为它会尝试并行执行每一次写入操作。这些都不是必需的。
我建议您将要编写的文本构建为字符串,并在最后执行一次写入,因为似乎没有理由单独编写每个文本。这也会更有效率:
writeToFile(entriesArray.map((entry) => {
return entry.id + ',' + entry.fname + ',' + entry.lname + ',' +
entry.address + ',' + entry.age + ',' + entry.sex + '\n';
}).join(""));
假设您entriesArray
中有1000件物品。您的方案是为每个条目打开,写入和关闭3000个磁盘操作。我建议的代码执行3次磁盘操作。这应该明显更快并且具有保证的写入顺序。
此外,您确实需要考虑正确的错误处理。使用类似的东西:
if (err) throw err;
在异步回调中是不正确的错误处理。这引发了一个你无法处理的异步事件。这是关于计划:
const writeToFile = (str, fn) => {
fs.appendFile(outputFileName + '.csv', str, (err) => {
fn(err);
});
};
writeToFile(entriesArray.map((entry) => {
return entry.id + ',' + entry.fname + ',' + entry.lname + ',' +
entry.address + ',' + entry.age + ',' + entry.sex + '\n';
}).join(""), function(err) {
if (err) {
// error here
} else {
// success here
}
});