How to write multiple files using Node.js createReadStream and createWriteStream
compression, javascript, node.js, pipe, png
Solution
You are repeatedly reassigning the output variable in your loop, while the request callback is trying to refer to it. You can capture each value in a closure to get around this.
...
function closureRequest(output){
return new https.request(options, function(response) {
if (response.statusCode === 201) {
/* Compression was successful, retrieve output from Location header. */
https.get(response.headers.location, function(response) {
response.pipe(output);
});
} else {
/* Something went wrong! You can parse the JSON body for details. */
console.log("Compression failed");
}
});
}
var input
, request
;
for(var i = 0; i < files.length; i++){
input = fs.createReadStream(inputFolder + files[i]);
request = closureRequest(fs.createWriteStream(outputFolder + files[i]));
input.pipe(request);
}
Problem
Okay here is the general goal of this code. I am using TinyPNG's API to condense a folder of png files. I have an input folder with a number of files named filename.png. This code reads the directory of file names into an array files, then creates read and write streams for those files to be sent to the API, processed, and then returned so it can be written to a file in the output folder. I know the code works for one file, but any more than that throws an exception of write after end because the pipe is automatically closed after the first one. I have tried setting up the input and output as arrays and that just throws another exception. Any hints on how to set up multiple read and write streams would be awesome and very useful to everyone :). Current code: ``` var fs = require('fs'); var inputFolder = "input/"; var outputFolder = "output/"; var https = require("https"); var key = "GETYOUROWNFREEONEFROMTINYPNG.ORG"; process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; var options = require("url").parse("https://api.tinypng.com/shrink"); options.auth = "api:" + key; options.method = "POST"; console.log("Reading files..."); fs.readdir("./input", function (err, files) { if (err) throw err; console.log(files.length + " files read..."); var input; var output; var request; for(var i = 0; i < files.length; i++) { input = fs.createReadStream(inputFolder + files[i]); output = fs.createWriteStream(outputFolder + files[i]); request = new https.request(options, function(response) { if (response.statusCode === 201) { /* Compression was successful, retrieve output from Location header. */ https.get(response.headers.location, function(response) { response.pipe(output); }); } else { /* Something went wrong! You can parse the JSON body for details. */ console.log("Compression failed"); } }); input.pipe(request); } }); ``` Here is the fixed file for others to use thanks to the answer provided by @Wyatt: ``` var fs = require('fs'); var inputFolder = "input/"; var outputFolder = "output/"; var https = require("https"); var key = "WotZ46HnxPl_HwpT3uZjtY_0f8fMEiSR"; process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; var options = require("url").parse("https://api.tinypng.com/shrink"); options.auth = "api:" + key; options.method = "POST"; console.log("Reading files..."); fs.readdir("./input", function (err, files) { if (err) throw err; console.log(files.length + " files read..."); var input, request; for(var i = 0; i < files.length; i++){ input = fs.createReadStream(inputFolder + files[i]); request = closureRequest(fs.createWriteStream(outputFolder + files[i])); input.pipe(request); } }); function closureRequest(output){ return new https.request(options, function(response) { if (response.statusCode === 201) { /* Compression was successful, retrieve output from Location header. */ https.get(response.headers.location, function(response) { response.pipe(output); }); } else { /* Something went wrong! You can parse the JSON body for details. */ console.log("Compression failed"); } }); } ```