Closed the0neWhoKnocks closed 6 years ago
You're right, that documentation is missing. I'll try and get an example put together soon. The crux of it would be to make an Archive object and add ArchiveFile's to it, then encode the archive with the ZipEncoder.
:laughing: yeah, I figured that much out. What I couldn't determine was the format in which to do that. Not sure how much effort it'd take for you to put an example together, but it'd be appreciated.
As I started looking into it, I realized the ZipEncoder could be made much better to support this type of thing. I had done it for creating tar files for directories (TarFileEncoder), since Dart pub was using tars, but hadn't done it for zip files. I should be done in a day or two.
I pushed a new version with the changes I added to make this easier. You can now zip a directory using:
import 'dart:io';
import 'package:archive/archive_io.dart';
main() {
new ZipFileEncoder().zipDirectory(new Directory('foo'), filename: 'foo.zip');
}
You can also create an Archive object for a disk directory using the new function:
Archive archive = createArchiveFromDirectory(new Directory('foo'));
Sweet! My use case needs to archive a mixture of files and folders, how would I go about that? Also, the first example you gave, is that synchronous or does it return a future? Would need the ability to wait until the archives been created.
It's synchronous.
ZipFileEncoder {
void zipDirectory(Directory dir, [String zip_filename]); // convenience function for doing the wrapping the following methods.
void open(String zip_path);
void addDirectory(Directory dir);
void addFile(File file, [String filename]); // filename is the stored in the zip, so it can be a path relative to the zip root.
void close();
}
var encoder = new ZipFileEncoder();
encoder.open('foo.zip');
encoder.addDirectory(new Directory('some_directory'));
encoder.addFile(new File('some_file'));
encoder.close();
Nothing in the library is async. If anyone wants async, they can put it in their own async wrapper. I don't do that much Dart programming these days, other than minimally maintaining a couple libraries I had written like this one, so I don't have much time to add any extensive changes like that to the library...my kids make sure I don't have that time :-)
I'll give this a try later.
Looks like example.dart
is the same in the new release. I imagine it'd be useful to others if that was updated with the examples you provided here - especially since it's kinda the point of this ticket :wink: .
Also, I'm assuming that encoder.open('foo.zip');
will create the file if it doesn't already exist. If it does, it could be more clear to the user if a pass through method of create
was added (which would then just call open
internally. So the above would then read - create, addDirectory, addFile, & close.
Anyway, thanks for the quick turn around.
So things are kind of working, in the sense that files are being added to a zip archive. I'm passing in absolute paths to files and directories formatted like so
/data/user/0/APP_NAME/app_flutter/file1.json
/data/user/0/APP_NAME/app_flutter/file2.json
/data/user/0/APP_NAME/app_flutter/someFolder
In the above imagine the contents of someFolder
are sub1.json
, sub2.json
.
The zip file contains this structure after I've called addFile
& addDirectory
on the above list.
/[folder_with_no_name]
/data
/user
/0
/APP_NAME
/app_flutter
- file1.json
- file2.json
- sub1.json
- sub2.json
The contents of the folder are being added individually instead of in the folder they were originally in, and the files are added in a nested folder structure matching their absolute path.
Ok, this is what I ended up with. Notice I had to inline the guts of addDirectory
since the relative
call wasn't referencing a parent directory (causing the contents to be outside of their original folder), the parent directory is workingDir
in this case.
String workingDir = '/data/user/0/APP_NAME/app_flutter';
String archivePath = 'archiveName.zip';
List<String> fileNames = [
'file1.json',
'file2.json',
'someFolder',
];
// create the file so the encoder has something to open
new File(archivePath);
// spin up a new encoder instance
ZipFileEncoder encoder = new ZipFileEncoder();
// iterate files and add them to the archive
encoder.open(archivePath);
fileNames.forEach((String currFile) {
String absPath = '$workingDir/$currFile';
if(FileSystemEntity.isFileSync(absPath)) {
encoder.addFile(
new File(absPath),
path.relative(absPath, from: workingDir)
);
}
else if(FileSystemEntity.isDirectorySync(absPath)){
Directory dir = new Directory(absPath);
List files = dir.listSync(recursive: true);
for(File file in files){
if(file is! File) continue;
encoder.addFile(
file,
path.relative(file.path, from: workingDir)
);
}
}
});
encoder.close();
Ah, you’re right, my bad. Guess I was trying to rush through it to quickly. I’ll add your fixes to make sure relative paths are stored when I get the chance later...and update the doc examples. I still haven’t figured out how pub expects to use that example.dart file. Doesn’t make much sense to me for how to put multiple examples there. The wiki makes more sense to me.
I made a couple changes, hopefully improve things.
void addDirectory(Directory dir, {bool includeDirName = true})
which will include the name of the directory in the file paths added from that directory.So, in your above example,
var encoder = new ZipFileEncoder();
encoder.create('archiveName.zip');
encoder.addFile(new File('/data/user/0/APP_NAME/app_flutter/file1.json'));
encoder.addFile(new File(/data/user/0/APP_NAME/app_flutter/file2.json'));
encoder.addDirectory(new Directory('/data/user/0/APP_NAME/app_flutter/someFolder'));
encoder.close();
should create a zip with:
file1.json
file2.json
someFolder/sub1.json
someFolder/sub2.json
I'm out of time for tonight, but I'll try and get the docs/examples updated soon and push out the release with the updates.
With the includeDirName
arg, would it maintain the full path from a specified directory? For example, if someFolder
had a file that was nested a couple folders deep, would it maintain the full directory structure, or would it flatten everything to be in just one folder?
Maybe just passing a workingDir
arg on creation of the encoder might be preferable. Then each addFile or addDirectory call would know what to base it's relative pathing on.
var encoder = new ZipFileEncoder({
workingDir: '/data/user/0/APP_NAME/app_flutter',
});
Relative paths are stored in both cases of includeDirName, it's just weather or not the directory name itself is included. If you have the following directory/files:
/data/user/0/APP_NAME/app_flutter/someFolder/subFolder/file1.json
/data/user/0/APP_NAME/app_flutter/someFolder/file2.json
Then:
addDirectory('/data/user/0/APP_NAME/app_flutter/someFolder', includeDirName: false)
Would store the files as:
subFolder/file1.json
file2.json
And
addDirectory('/data/user/0/APP_NAME/app_flutter/someFolder', includeDirName: true)
Woud store the files as:
someFolder/subFolder/file1.json
someFolder/file2.json
In most cases where you're manually adding directories, including the directory name makes sense; if your just zipping a directory by itself, it makes sense to not include the directory (like if you run gzip to compress a directory.)
Not that this is a great API, but I'm a bit worried about the workingDir solution being a bit specific.
Fair enough, so long long as it maintains the proper file/folder structure I'm good :+1:
I pushed 2.0.2 with the updates, and included the basic usage in example.dart.
Cool. Good work on this. Close this puppy out whenever you feel like it. :heavy_check_mark:
Perhaps it's not possible with this package, but I can't figure out how to create a new Archive from files within my app. For example I want to zip up some files within a sub-directory of my app. All the examples only call out manipulating an already existing archive file.