Thread overview |
---|
February 03, 2020 Is there a std.zip.ZipArchive isDir or isFile method? | ||||
---|---|---|---|---|
| ||||
I'm using std.zip.ZipArchive to read zip files, e.g.: auto zip = new ZipArchive(read(filename)); // ... foreach (name, member; zip.directory) { if (name.endsWith('/')) // skip dirs continue; mkdirRecurse(dirName(name)); zip.expand(member); write(name, member.expandedData()); } As you can see, I am detecting directories with a crude test. I really wish there was a method for this: and if there is, could you give me the link 'cos I can't see one in the docs? (BTW The code above is slightly simplified: the real code won't unzip if there's an absolute path or .. present and also ensures that all members are unzipped into a subdir even if the zip has top-level names.) |
February 03, 2020 Re: Is there a std.zip.ZipArchive isDir or isFile method? | ||||
---|---|---|---|---|
| ||||
Posted in reply to mark | On Monday, 3 February 2020 at 13:26:38 UTC, mark wrote:
> I'm using std.zip.ZipArchive to read zip files, e.g.:
>
> auto zip = new ZipArchive(read(filename));
> // ...
> foreach (name, member; zip.directory) {
> if (name.endsWith('/')) // skip dirs
> continue;
> mkdirRecurse(dirName(name));
> zip.expand(member);
> write(name, member.expandedData());
> }
>
> As you can see, I am detecting directories with a crude test.
>
> I really wish there was a method for this: and if there is, could you give me the link 'cos I can't see one in the docs?
>
> (BTW The code above is slightly simplified: the real code won't unzip if there's an absolute path or .. present and also ensures that all members are unzipped into a subdir even if the zip has top-level names.)
ArchiveMember has "flags" field, perhaps it stores if it's a directory?
If not, fileAttributes will have it but it looks it's OS specific.
|
February 12, 2020 Re: Is there a std.zip.ZipArchive isDir or isFile method? | ||||
---|---|---|---|---|
| ||||
Posted in reply to mark | On Monday, 3 February 2020 at 13:26:38 UTC, mark wrote: > I'm using std.zip.ZipArchive to read zip files, e.g.: > > auto zip = new ZipArchive(read(filename)); > // ... > foreach (name, member; zip.directory) { > if (name.endsWith('/')) // skip dirs > continue; > mkdirRecurse(dirName(name)); > zip.expand(member); > write(name, member.expandedData()); > } > > As you can see, I am detecting directories with a crude test. > > I really wish there was a method for this: and if there is, could you give me the link 'cos I can't see one in the docs? > > (BTW The code above is slightly simplified: the real code won't unzip if there's an absolute path or .. present and also ensures that all members are unzipped into a subdir even if the zip has top-level names.) I couldn't find one either, I had to do this: version(Windows) { enum uint FILE_ATTRIBUTE_DIRECTORY = 0x10; } auto zip = new ZipArchive(buffer); foreach (fn, am; zip.directory) { if (am.fileAttributes & FILE_ATTRIBUTE_DIRECTORY) ... is directory else ... is file } As I'm looking at my code for this I'm also reminded that different zip files can internally store path separators as either \ or / depending on the platform that created them so you may need to be careful about that too. I have a bit for this that simply does: version(StandardizePathSeparators) { string filename = fn.replace("\\", "/"); } else { string filename = fn; } |
February 12, 2020 Re: Is there a std.zip.ZipArchive isDir or isFile method? | ||||
---|---|---|---|---|
| ||||
Posted in reply to cc | On Wednesday, 12 February 2020 at 05:59:53 UTC, cc wrote: > On Monday, 3 February 2020 at 13:26:38 UTC, mark wrote: >> I'm using std.zip.ZipArchive to read zip files, e.g.: [snip] > I couldn't find one either, I had to do this: > > version(Windows) { > enum uint FILE_ATTRIBUTE_DIRECTORY = 0x10; > } > auto zip = new ZipArchive(buffer); > foreach (fn, am; zip.directory) { > if (am.fileAttributes & FILE_ATTRIBUTE_DIRECTORY) > ... is directory > else > ... is file > } I need to work on both Linux and Windows, and on Linux am.fileAttributes seems to be 0 for both files and directories. The lack of a cross-platform way of distinguishing whether an archive member is a directory or file does seem to be a missing piece of the API. > As I'm looking at my code for this I'm also reminded that different zip files can internally store path separators as either \ or / depending on the platform that created them so you may need to be careful about that too. I have a bit for this that simply does: > version(StandardizePathSeparators) { > string filename = fn.replace("\\", "/"); > } else { > string filename = fn; > } Yes, I was aware of that, but I use: string filename = fn.tr("\\", "/"); // tr is from std.string |
February 12, 2020 Re: Is there a std.zip.ZipArchive isDir or isFile method? | ||||
---|---|---|---|---|
| ||||
Posted in reply to mark | It looks like 0040000 (octal) is the flag for directories on linux, but it does seem that std.zip is explicitly returning 0 if the file was created on the opposite platform re: Posix vs Windows, which is... odd. @property @nogc nothrow uint fileAttributes() const { version (Posix) { if ((_madeVersion & 0xFF00) == 0x0300) return _externalAttributes >> 16; return 0; } else version (Windows) { if ((_madeVersion & 0xFF00) == 0x0000) return _externalAttributes; return 0; } else { static assert(0, "Unimplemented platform"); } } Looks like the only way around it is modifying std.zip? Adding something like: @property bool isDir() const { enum uint FILE_ATTRIBUTE_DIRECTORY = 0x10; // WINNT.h enum uint S_IFDIR = 0x4000; // sys/stat.h version(Windows) { if ((_madeVersion & 0xFF00) == 0x0300) // Archive made on Posix return cast(bool) (_externalAttributes & (S_IFDIR << 16)); return cast(bool) (_externalAttributes & FILE_ATTRIBUTE_DIRECTORY); } else version(Posix) { if ((_madeVersion & 0xFF00) == 0x0300) // Archive made on Posix return cast(bool) (_externalAttributes & (S_IFDIR << 16)); return cast(bool) ((_externalAttributes) & FILE_ATTRIBUTE_DIRECTORY); } else { static assert(0, "Unimplemented platform"); } } will let me do this: void main() { foreach (zipfile; ["windowstest.zip", "linuxtest.zip"]) { writeln(zipfile); auto zip = new ZipArchive(std.file.read(zipfile)); foreach (fn, am; zip.directory) { writefln("%24s %5s %s", fn, am.isDir, am.fileAttributes); } } } Results on Windows: windowstest.zip a.txt false 32 testdir/ true 16 testdir/b.txt false 32 linuxtest.zip a.txt false 0 testdir/ true 0 testdir/b.txt false 0 Results on Linux: windowstest.zip testdir/ true 0 testdir/b.txt false 0 a.txt false 0 linuxtest.zip testdir/ true 16893 testdir/b.txt false 33204 a.txt false 33204 |
Copyright © 1999-2021 by the D Language Foundation