2016-08-08 31 views
1

Ich baue eine Web-App mit Node.js, und ich bin an einem Punkt, wo ich ein Tar-Archiv erstellen muss eines Verzeichnisses von PDFs. Die Anwendung läuft auf einer VM mit Ubuntu 14.04 Server. Mein Code, dies zu tun ist unten dargestellt:Node.js - Exec-Befehl für TAR-Dateien funktioniert beim ersten Mal korrekt, erzeugt aber bei der nächsten Ausführung fehlerhafte tar-Inhalte

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

und diese tarDirectory Funktion durch den folgenden Code aufgerufen wird:

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

Der Code erwartet eine Post-Anforderung mit dynamischen Daten, die durch Klicken auf eine Schaltfläche erzeugt wird in meiner Web-App, und wird dann Dateien basierend auf den Daten erstellen und es in ein Verzeichnis tarieren. Das alles funktioniert gut und gut ... das erste Mal. Wenn ich zum ersten Mal auf den Knopf klicke, wird das Tar erzeugt, und wenn ich es öffne, sind die clientseitigen PDFs identisch mit denen auf dem Server. Wenn ich innerhalb einer Stunde erneut klicke, erhalte ich zwar eine TAR-Datei, aber wenn ich das Archiv öffne und entpacke, sind die PDFs alle beschädigt und etwa die Hälfte der erwarteten Byte-Größe. Ich bin hier ratlos ... Ich hatte den Verdacht, dass es mit der unsachgemäßen Handhabung des Schließens von Strom in Verbindung stehen könnte, aber ich bin mir nicht sicher.

Dies ist der Code, der die PDF-Dateien in ein Verzeichnis erzeugt, die dann nach der Erzeugung geteert:

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

Antwort

0
  1. Ist alles in Ordnung mit PDF-Dateien, bevor Komprimierung?
  2. In Ihrer generateFile Funktion haben Sie WriteStream, das async ist. Sie nennen diese Funktion jedoch sync. Und starten die .tar-Komprimierung, ohne zu warten, bis die PDF-Generierung abgeschlossen ist, was zu diesem Problem führen kann.
  3. Als Empfehlung: Versuchen Sie, generateFile mit Versprechen, oder iterieren async., Und starten Sie die Komprimierung erst nach der Erstellung aller Dateien.

Beispiel mit drossel:

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 Erzeugung und komprimieren.

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 
    }); 
+0

1. Ja, die PDFs sind in ihren ursprünglichen Ordnern auf dem Server intakt, so dass sie definitiv korrekt generiert werden. 2. Ich denke, dass dies auf dem richtigen Weg ist ... Ich werde versuchen, dafür Versprechungen zu verwenden. 3.Danke für das Beispiel :) – Kw3si

+0

Also, nachdem ich Ihren Vorschlag von Versprechungen umgesetzt hatte, war ich in der Lage, es zu einem Punkt zu bringen, wo es die PDFs richtig erzeugt, wenn es nur eins zu einer Zeit erzeugt. Untersuchung ... wird zu dir zurückgehen – Kw3si

0

Also habe ich die Versprechen umgesetzt, die Nazar vorgeschlagen hat. Die gesamte Operation funktioniert jetzt am besten, wenn ich nur eine Datei erzeuge, aber wenn ich mehr erzeuge, bekomme ich die gleichen beschädigten PDFs.

Mein Code die einzelnen Dateien zu generieren:

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

Mein Code auf das Verzeichnis 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(); 
    }); 
    }); 
} 

und mein Code, der die zwei Hilfsfunktionen aufruft:

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

Irgendwelche weiteren Erkenntnisse darüber, was ich hier falsch machen könnte, werden sehr geschätzt.

+0

mach die nächste: 'function generateFile', ersetze' resolve() 'mit' resolve ({id: id, pfad: filePath}) '. und in 'Promise.map' - zuerst' .then (function() 'mit' then (function (files) '. Drucken Sie diese Dateien, um sicherzustellen, dass die Namen korrekt sind. Es gibt nicht genug Informationen. Und mein Gedanke, dass Sie haben versucht, in die gleiche Datei zu schreiben. " –

+0

Ich löste das Problem. Es stammte von der Tatsache, dass ich das Versprechen, das in Promise.map() generiert wurde, nicht zurückgab. Cheers für all Ihre Hilfe Nazar. – Kw3si