我更新了功能以创建CSV文件,但是现在出现错误:
上载功能 内部/流/legacy.js:57 投掷者//管道中未处理的流错误。 ^
错误:ENOENT:没有此类文件或目录,请打开“ C:\ Users \ shiv \ WebstormProjects \ slackAPIProject \ billingData \ CSV \ 1548963844106output.csv”
var csvFilePath = '';
var JSONFilePath = '';
function sendBillingData(){
var message = '';
axios.get(url, {
params: {
token: myToken
}
}).then(function (response) {
message = response.data;
fields = billingDataFields;
// saveFiles(message, fields, 'billingData/');
saveFilesNew(message, fields, 'billingData/');
var file = fs.createReadStream(__dirname + '/' + csvFilePath); // <--make sure this path is correct
console.log(__dirname + '/' + csvFilePath);
uploadFile(file);
})
.catch(function (error) {
console.log(error);
});
}
saveFilesNew函数为:
function saveFilesNew(message, options, folder){
try {
const passedData = message;
var relevantData='';
if (folder == 'accessLogs/'){
const loginsJSON = message.logins;
relevantData = loginsJSON;
console.log(loginsJSON);
}
if(folder == 'billingData/'){
relevantData = passedData.members;
const profile = passedData.members[0].profile;
}
//Save JSON to the output folder
var date = Date.now();
var directoryPath = folder + 'JSON/' + date + "output";
JSONFilePath = directoryPath + '.json';
fs.writeFileSync(JSONFilePath, JSON.stringify(message, null, 4), function(err) {
if (err) {
console.log(err);
}
});
//parse JSON onto the CSV
const json2csvParser = new Json2csvParser({ fields });
const csv = json2csvParser.parse(relevantData);
// console.log(csv);
//function to process the CSV onto the file
var directoryPath = folder + 'CSV/' + date + "output";
csvFilePath = directoryPath + '.csv';
let data = [];
let columns = {
real_name: 'real_name',
display_name: 'display_name',
email: 'email',
account_type: 'account_type'
};
var id = passedData.members[0].real_name;
console.log(id);
console.log("messageLength is" +Object.keys(message.members).length);
for (var i = 0; i < Object.keys(message.members).length; i++) {
console.log("value of i is" + i);
var display_name = passedData.members[i].profile.display_name;
var real_name = passedData.members[i].profile.real_name_normalized;
var email = passedData.members[i].profile.email;
var account_type = 'undefined';
console.log("name: " + real_name);
if(passedData.members[i].is_owner){
account_type = 'Org Owner';
}
else if(passedData.members[i].is_admin){
account_type = 'Org Admin';
}
else if(passedData.members[i].is_bot){
account_type = 'Bot'
}
else account_type = 'User';
data.push([real_name, display_name, email, account_type]);
}
console.log(data);
stringify(data, { header: true, columns: columns }, (err, output) => {
if (err) throw err;
fs.writeFileSync(csvFilePath, output, function(err) {
console.log(output);
if (err) {
console.log(err);
}
console.log('my.csv saved.');
});
});
} catch (err) {
console.error(err);
}
}
上传文件功能为:
function uploadFile(file){
console.log("In upload function");
const form = new FormData();
form.append('token', botToken);
form.append('channels', 'testing');
form.append('file', file);
axios.post('https://slack.com/api/files.upload', form, {
headers: form.getHeaders()
}).then(function (response) {
var serverMessage = response.data;
console.log(serverMessage);
});
}
所以我认为是由于节点试图在创建文件之前上载文件而引起的错误。我觉得这与Node.js的异步特性有关,但是我无法理解如何纠正代码。请让我知道如何纠正此问题,并同时提及对代码结构/设计的任何改进。 谢谢!
答案 0 :(得分:1)
您不必等待提供给stringify
的回调函数的执行,而这正是您创建文件的地方。 (假设此stringify
函数确实接受了回调。)
使用回调(您可以使用promises和这些整洁的async
/ await
控件使这个更简洁,但让我们在这里仅坚持使用回调),它应该更像是:
function sendBillingData() {
...
// this callback we'll use to know when the file writing is done, and to get the file path
saveFilesNew(message, fields, 'billingData/', function(err, csvFilePathArgument) {
// this we will execute when saveFilesNew calls it, not when saveFilesNew returns, see below
uploadFile(fs.createReadStream(__dirname + '/' + csvFilePathArgument))
});
}
// let's name this callback... "callback".
function saveFilesNew(message, options, folder, callback) {
...
var csvFilePath = ...; // local variable only instead of your global
...
stringify(data, { header: true, columns: columns }, (err, output) => {
if (err) throw err; // or return callbcack(err);
fs.writeFile(csvFilePath , output, function(err) { // NOT writeFileSync, or no callback needed
console.log(output);
if (err) {
console.log(err);
// callback(err); may be a useful approach for error-handling at a higher level
}
console.log('my.csv saved.'); // yes, NOW the CSV is saved, not before this executes! Hence:
callback(null, csvFilePath); // no error, clean process, pass the file path
});
});
console.log("This line is executed before stringify's callback is called!");
return; // implicitly, yes, yet still synchronous and that's why your version crashes
}
使用仅在预期事件发生时(文件已完成写,缓冲区/字符串已完成转换...)才调用的回调使JS可以在此期间继续执行代码。而且它确实会继续执行代码,因此当您需要异步代码中的数据时,需要在执行代码之前告诉JS您需要完成它。
此外,由于您可以在回叫时传递数据(这只是一个函数),因此在这里我可以避免依赖全局csvFilePath
。使用更高级别的变量使事情变得单一,就像您无法将saveFilesNew
转移到专用文件中一样,该文件中保留了文件相关功能的工具包。
最后,如果您的全局流程如下:
function aDayAtTheOffice() {
sendBillingData();
getCoffee();
}
那么您就无需在开始煮咖啡之前就等待计费数据处理完毕了。但是,如果老板告诉您在结算帐单数据之前无法喝咖啡,那么您的流程将如下所示:
function aDayAtTheOffice() {
sendBillingData(function (err) {
// if (err) let's do nothing here: you wanted a coffee anyway, right?
getCoffee();
});
}
(请注意,具有潜在错误的回调是第一个arg,数据是第二个arg,这是惯例,没有强制性。)
恕我直言,您应该阅读scope(在已经callback
的调用已经被忘记的时候可以访问参数saveFilesNew
)和{{3} }。 ;)(很抱歉,可能不是最好的链接,但它们包含有意义的关键字,然后Google是您的好友,您的朋友,您的老大哥。)