Search code examples
javascriptnode.jszipvscode-extensionsdynamics-business-central

Extract a non ZIP file to files on disk?


I got a App File which is structured like a zip file. Now I would like to extract all of the files in the app file.

I tried to convert the app to a zip file in the code (just copy and paste as zip file), but then it's a "SFX ZIP Archive", which most of the unzipper in node.js can't read.

For example AdmZip (error message):

rejected promise not handled within 1 second: Error: Invalid CEN header (bad signature)

var AdmZip = require('adm-zip');
var admZip2 = new AdmZip("C:\\temp\\Test\\Microsoft_System.zip");
admZip2.extractAllTo("C:\\temp\\Test\\System", true)

So now i don't know how to deal with it, because I need to extract the files with all subfolder/subfiles to a specific folder on the computer.

How would you do this?

You can download the .app file here:

https://drive.google.com/file/d/1i7v_SsRwJdykhxu_rJzRCAOmam5dAt-9/view?usp=sharing

If you open it, you should see something like this:

App file in WinRar

Thanks for your help :)

EDIT:

I'm already using JSZip for resaving the zip file as a normal ZIP Archive. But this is a extra step which costs some time.

Maybe someone knows how to extract files to a path with JSZip :)

EDIT 2:

Just for you information: It's a VS Code Extension Project

EDIT 3: I got something which worked for me. For my solution I did it with Workers (Because parallel)

var zip = new JSZip();
zip.loadAsync(data).then(async function (contents) {
zip.remove('SymbolReference.json');
zip.remove('[Content_Types].xml');
zip.remove('MediaIdListing.xml');
zip.remove('navigation.xml');
zip.remove('NavxManifest.xml');
zip.remove('Translations');
zip.remove('layout');
zip.remove('ProfileSymbolReferences');
zip.remove('addin');
zip.remove('logo');

//workerdata.files = Object.keys(contents.files)
//so you loop through contents.files and foreach file you get the dirname
//then check if the dir exists (create if not)
//after this you create the file with its content
//you have to rewrite some code to fit your code, because this whole code are
//from 2 files, hope it helps someone :)

Object.keys(workerData.files.slice(workerData.startIndex, workerData.endIndex)).forEach(function (filename, index) {
  workerData.zip.file(filename).async('nodebuffer').then(async function (content) {
    var destPath = path.join(workerData.baseAppFolderApp, filename);
    var dirname = path.dirname(destPath);

    // Create Directory if is doesn't exists
    await createOnNotExist(dirname);

    files[index] = false;
    fs.writeFile(destPath, content, async function (err) {
        // This is code for my logic
        files[index] = true;
        if (!files.includes(false)) {
            parentPort.postMessage(workerData);
        };
    });
  });
});

Solution

  • jsZip is A library for creating, reading and editing .zip files with JavaScript, with a lovely and simple API.

    link (https://www.npmjs.com/package/jszip)

    example (extraction)

    var JSZip = require('JSZip');
    
    fs.readFile(filePath, function(err, data) {
        if (!err) {
            var zip = new JSZip();
            zip.loadAsync(data).then(function(contents) {
                Object.keys(contents.files).forEach(function(filename) {
                    zip.file(filename).async('nodebuffer').then(function(content) {
                        var dest = path + filename;
                        fs.writeFileSync(dest, content);
                    });
                });
            });
        }
    });