用于tar文件的Node.js-exec命令第一次可以正常工作,但在后续执行时会产生损坏的tar内容

用于tar文件的Node.js-exec命令第一次可以正常工作,但在后续执行时会产生损坏的tar内容,node.js,linux,tar,Node.js,Linux,Tar,我正在用Node.js构建一个web应用程序,现在我需要生成PDF目录的tar存档。该应用程序运行在运行Ubuntu 14.04服务器的VM上。我的代码如下所示: function tarDirectory(path, token, callback) { var exec = require('child_process').exec; var cmd = 'cd ' + path + ' && tar -cvf genericName-' + token + '.ta

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

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();
  });
}
此tarDirectory函数由以下代码调用:

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请求,该请求包含通过在我的web应用程序中单击按钮生成的动态数据,然后将基于该数据创建文件并将其放入目录中。这一切都很好。。。第一次。当我在一段时间内第一次单击该按钮时,会生成tar,当我打开它时,客户端PDF与服务器上的PDF完全相同。不过,当我在一个小时左右再次单击时,我会收到一个tar文件,但当我打开归档文件并将其解压缩时,PDF文件都已损坏,大约是预期字节大小的一半。我在这里不知所措。。。我怀疑这可能与流关闭的不当处理有关,但我不确定

这是将PDF生成到目录中的代码,该目录在生成后会涂上焦油:

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();
}
  • 压缩之前,pdf文件一切正常吗
  • generateFile
    函数中,您有WriteStream,它是异步的。但是,您将此函数称为sync.,并在pdf生成完成之前启动.tar压缩,这可能会导致此问题
  • 建议:尝试使用promise包装
    generateFile
    ,或迭代异步,并仅在所有文件生成完成后才开始压缩
  • 以蓝鸟为例:

    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();
      });
    }
    
    PDF生成和压缩

     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文件一切正常吗
  • generateFile
    函数中,您有WriteStream,它是异步的。但是,您将此函数称为sync.,并在pdf生成完成之前启动.tar压缩,这可能会导致此问题
  • 建议:尝试使用promise包装
    generateFile
    ,或迭代异步,并仅在所有文件生成完成后才开始压缩
  • 以蓝鸟为例:

    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();
      });
    }
    
    PDF生成和压缩

     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();
        });
      });
    }
    
    以及我调用两个helper函数的代码:

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

    对于我在这里可能犯下的错误的任何进一步见解,我都非常感激。

    因此我实现了纳扎尔提出的承诺。如果我只生成一个文件,那么整个操作现在可以正常工作,但是如果生成更多文件,则会得到相同的损坏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();
        });
      });
    }
    
    以及我调用两个helper函数的代码:

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

    如果您能进一步了解我在这里可能犯的错误,我们将不胜感激。

    1。是的,PDF在服务器上的原始文件夹中完好无损,因此它们肯定是正确生成的。2.我认为这是在正确的轨道上。。。我将考虑为此使用承诺。3.感谢您提供的示例:)因此,在实施您的承诺建议后,我能够让它正确地生成PDF,如果它一次只生成一个PDF。调查。。。我会回复你的。是的,PDF在服务器上的原始文件夹中完好无损,因此它们肯定是正确生成的。2.我认为这是在正确的轨道上。。。我将考虑为此使用承诺。3.感谢您提供的示例:)因此,在实施您的承诺建议后,我能够让它正确地生成PDF,如果它一次只生成一个PDF。调查。。。将返回给您执行下一步操作:
    function generateFile
    ,将
    resolve()
    替换为
    resolve({id:id,path:filePath})
    。在
    Promise.map
    -首先
    。然后(function()
    )与
    一起,然后(function(files)
    。打印此文件,以验证名称是否正确。没有足够的信息。我认为您试图写入同一个文件。我解决了此问题。这是因为我没有返回promise.map()中生成的承诺.Nazar.为您的帮助干杯。执行下一步:
    function generateFile
    ,将
    resolve()
    替换为
    resolve({id:id,path:filePath})
    。并在
    Promise.map中,首先将
    映射为
    ,然后将
    替换为
    ,然后再替换为
    函数(文件)
    。打印此文件,以验证名称是否正确。没有足够的信息。我认为您试图写入同一个文件。我解决了问题。这是因为我没有返回promise.map()中生成的承诺。为您的帮助干杯。