adm-zip
adm-zip copied to clipboard
Directories are ignored in zip file
I've got a zip file created from https://makeappicon.com. It consists of three subdirectories each containing some image files and folders.

When opening this .zip file with adm-zip (v0.5.9) and reading the getEntries() contents, there are no directories, just files.

However when using extractAllTo(), the folder structure is preserved and files are extracted into subdirectories.
How to I get the files from within one subdirectory? Using extractEntryTo("ios/", false, true) returns an entry not found error.
Same issue Windows 11 Node.js v18.9.0
Likewise, I tried to list all the child entries out of a particular directory inside the zip archive.
getEntryChildren sounded like what I was looking for, so I tried code like:
const dir = zip.getEntry(dirName);
for (const entry of zip.getEntryChildren(dir) {
if (!entry.isDirectory) {
...
}
}
But it didn't work. When I went debugging, I found that dir was null even though dirName is definitely a directory within the zip.
I think it's normal for directories to not show up as distinct "entries" in the zip archive. Maybe there's multiple ways to represent this in an archive, but certainly I'm used to seeing entries for regular files only. So this approach taken by adm-zip of first getting the directory "entry" is just plain not going to work. ZipFile.getEntryChildren will never return anything, and ZipEntry.isDirectory will always be false.
I worked around it by iterating over all the entries and testing for the directory prefix, using code like the below. Not ideal but right now I think it's the best we can do.
/*
* Get a list of regular file entries under a directory.
*
* All descendants of the directory are returned, regardless of depth.
*/
export function getChildEntries(zip: Zip, dirName: string): ZipEntry[] {
let prefix = dirName;
if (!prefix.endsWith('/')) {
prefix += '/';
}
const entries = zip.getEntries();
if (!entries) {
return [];
}
// seems like `isDirectory` can never be true anyway, but just to be safe ...
return entries.filter(x => !x.isDirectory && x.entryName.startsWith(prefix));
}