Search code examples
javascriptnode.jsexpresshttpzip

convert zip file stream into a file on disk


i have a Node application (called MiddleOne) from which I hit my other Node App (called BiServer). the BiServer has only 1 route as follows

app.get("/", (req, res) => {
  const file = `./zipFiles.zip`;
  return res.download(file);
});

"MiddleOne" App sends request to "BiServer" and gets the file(a .zip file containing a single .json file) however i am not able to reconstruct and save that .zip file on my "MiddleOne" server .

http
    .get("BiServer:3009", resp => {
      let data = "";

      resp.on("data", chunk => {
        data += chunk;
      });

      resp.on("end", () => {

        fs.writeFile("./filename.zip", data, err => {
          console.log(err ? "Error: " + err : "File saved");
          return res.send("file is saved on server");
        });
      });
    })
    .on("error", err => {
      console.log("Error: " + err.message);
    });

the data object above has following content:

"PK
�T6P    zipFiles/PK�T6P�E8FIzipFiles/zipFiles.json����R*K-*���S�RP�s
W�
��$VZ(Y))股k^zQ�Bjnbf�Bf�BAbq�/W-//PK
�T6P    $zipFiles/
 �c�����c����&�8����PK�T6P�E8FI$ 'zipFiles/zipFiles.json
 K�#����K�#����H�����PK��"

on opening the newly created file error comes that the "file is corrupted" . how can i reconstruct the zip file on receiving response from other server ?


Solution

  • writeFile is used to write into a file, In your case, you are saving data as a string. Having a zip extension to a file doesn't guarantee it to be a zip file. You are actually writing string(unreadable chunks) to a file hence you are not getting an unreadable text file instead of a zip file. Try converting the chunks into a buffer, this should work:

    http
        .get("BiServer:3009", resp => {
          let chunks = [];
    
          resp.on("data", chunk => {
            chunks.push(chunk);
          });
         //Don't use end, close is the last event and you should always cleanup in this
          resp.on("close", () => {
            fs.writeFile("./filename.zip", Buffer.concat(chunks), err => {
              console.log(err ? "Error: " + err : "File saved");
              return res.send("file is saved on server");
            });
          });
        })
        .on("error", err => {
          console.log("Error: " + err.message);
        });
    

    Also, it will consume much memory as you are loading all data into memory before writing into a file and if the file size is very large you will face memory-related issues. So instead of saving the whole file in memory. you should try streams, Try this :

    const fs=require("fs");
    http
        .get("BiServer:3009", resp => {
          const fileWriteStream=fs.createWriteStream("fileName.zip");
          resp.pipe(fileWriteStream);
          resp.on("close", () => {
            Console.log("File written successfully.")
          });
        })
        .on("error", err => {
          console.log("Error: " + err.message);
        });