Node.js - tar 文件的 exec 命令第一次运行正常,但在后续执行时产生损坏的 tar 内容

Node.js - exec command for tar files works correctly first time, but produces corrupted tar contents upon subsequent execution

我正在使用 Node.js 构建一个网络应用程序,我正处于需要生成 PDF 目录的 tar 存档的时刻。该应用程序 运行 在 VM 运行 Ubuntu 14.04 服务器上。我的代码如下所示:

function tarDirectory(path, token, callback) {
  var exec = require('child_process').exec;
  var cmd = 'cd ' + path + ' && tar -cvf genericName-' + token + '.tar' + ' ' + token;

  exec(cmd, function(error, stdout, stderr) {
    console.log(stdout);
    console.log(stderr);
    if (error) {
      console.error(error);
    }
    if(callback) callback();
  });
}

而这个tar目录函数由以下代码调用:

router.post('/files/generate', function(req, res, next) {
  IDList = req.body['IDs[]'];
  token = req.body['token'];

  // if just a single file being generated
  if (typeof req.body['IDs[]'] === "string"){
      filehelper.generateFile(IDList[0], req.app.locals.site.basedir + "temp/", token);
  }
  // if multiple files being generated
  else {
    IDList.forEach(function(id) {
      filehelper.generateFile(id, req.app.locals.site.basedir + "temp/", token);
    });
  }
  filehelper.tarDirectory(req.app.locals.site.basedir + "temp/", token, res.end);
});

该代码需要一个 post 请求,其中包含通过在我的网络应用程序中单击按钮生成的动态数据,然后将根据数据创建文件并将其 tar 放入目录中。这一切都很好……第一次。当我第一次点击按钮时,会生成 tar ,当我打开它时,客户端的 PDF 与服务器上的相同。但是,当我在大约一个小时内再次单击时,我收到了一个 tar 文件,但是当我打开存档并将其解压缩时,PDF 全部损坏并且大约是预期字节大小的一半。我在这里不知所措......我怀疑这可能与流关闭处理不当有关,但我不确定。

这是将 PDF 生成到目录中的代码,生成后 tar 红色:

function generateFile(id, path, token) {
  var dirPath = path + token;
  var filePath = path + token + "/file" + id + ".pdf";

  console.log("creating file for: " + id);

  try{
    fs.statSync(dirPath).isDirectory();
  } catch (err) {
    fs.mkdirSync(dirPath);
  }
  // start the file pdf generation
  file = new PDFDocument();
  output = fs.createWriteStream(filePath);
  output.on('close', function(){
    return;
  });

  file.pipe(output);

  // handle the intricacies of the file generation
  file.text("file" + id + ".pdf");

  // end the file
  file.end();
}
  1. 压缩前 pdf 文件是否一切正常?
  2. 在您的 generateFile 函数中,您有 WriteStream,它是异步的。但是,您将此函数称为 sync.,并且 start .tar 压缩而没有等待 pdf 生成完成,这可能会导致此问题。
  3. 作为建议:尝试用 promise 包装 generateFile,或者迭代异步,并且仅在所有文件生成完成后才进行 tart 压缩。

蓝鸟示例:

var Promise = require('bluebird');

function generateFile(id, path, token) {
  return new Promise(function(resolve, reject) {
  var dirPath = path + token;
  var filePath = path + token + "/file" + id + ".pdf";

  console.log("creating file for: " + id);

  try{
    fs.statSync(dirPath).isDirectory();
  } catch (err) {
    fs.mkdirSync(dirPath);
  }
  // start the file pdf generation
  file = new PDFDocument();
  output = fs.createWriteStream(filePath);
  output.on('close', function(){
    return resolve();
  });

  output.on('error', function(error) {
    return reject(error);
  });

  file.pipe(output);

  // handle the intricacies of the file generation
  file.text("file" + id + ".pdf");

  // end the file
  file.end();
  });
}

Pdfs 生成和压缩。

 var Promise = require('bluebird');

    ....

    //IDList.forEach(function(id) {
    //      filehelper.generateFile(id, req.app.locals.site.basedir + "temp/", //token);});

    //replace with

    Promise.map(IDList, function(id) {
      return filehelper.generateFile(id, req.app.locals.site.basedir + "temp/", token);
    })
    .then(function() {
    //all files are ready, start compressing
    })
    .catch(function(error) {
    //we have error
    });

所以我实现了纳扎尔建议的承诺。如果我只生成一个文件,整个操作现在基本上可以正常工作,但如果我生成更多文件,我会得到相同的损坏 PDF。

我生成单个文件的代码:

function generateFile(id, path, token) {
  return new Promise(function(resolve, reject){
    var dirPath = path + token;
    var filePath = path + token + "/file" + id + ".pdf";

    console.log("creating file for: " + id);

    try{
      fs.statSync(dirPath).isDirectory();
    } catch (err) {
      fs.mkdirSync(dirPath);
    }
    // start the file pdf generation
    file = new PDFDocument();
    output = fs.createWriteStream(filePath);

    // stream handling
    output.on('finish', function(){
      console.log(fs.statSync(filePath)["size"]);
      return resolve();
    });

    output.on('error', function(error) {
      return reject(error);
    });

    // pipe the generated PDF to the output file
    file.pipe(output);

    // handle the intricacies of the transcript generation
    file.text("file" + id + ".pdf");

    // end the file
    file.end();
  });
}

我的代码到tar目录:

function tarDirectory(path, token) {
  return new Promise(function(resolve, reject){
    var exec = require('child_process').exec;
    var cmd = 'cd ' + path + ' && tar -cvf Files-' + token + '.tar' + ' ' + token;

    exec(cmd, function(error, stdout, stderr) {
      if (stdout != "") console.log(stdout);
      if (stderr != "") console.log(stderr);
      if (error) return reject(error);
      return resolve();
    });
  });
}

以及调用两个辅助函数的代码:

// submit request to generate files
router.post('/files/generate', function(req, res, next) {
  IDList = req.body['IDs[]'];
  token = req.body['token'];

  // convert single fileID into list because Promise.map() needs iterable
  if (typeof IDList === "string") {
    IDList = [IDList];
  }

  Promise.map(IDList, function(id) {
    filehelper.generateFile(id, req.app.locals.site.basedir + "temp/", token);
  })
  .then(function() {
    return filehelper.tarDirectory(req.app.locals.site.basedir + "temp/", token);
  })
  .then(function() {
    res.end();
  })
  .catch(function(error) {
    throw new Error('Something went wrong while generating the tar file! :(\n' + error);
  });
});

非常感谢任何关于我在这里可能做错了什么的进一步见解。