native_zip 0.8.4 copy "native_zip: ^0.8.4" to clipboard
native_zip: ^0.8.4 copied to clipboard

A FFI plugin for fast, easy-to-use, multi-threaded ZIP file operations.

native_zip #

A Flutter FFI plugin for fast, easy-to-use, multi-threaded ZIP file operations.
Implemented in native C code, using well-known libraries zlib and libzip.

Platform Support #

Windows Android Linux macOS iOS web

Help
Wanted

Never
support

For iOS & macOS platform ( Help Wanted ) #

In theory, this package should be able to run on both iOS and macOS. Since I have no iOS or macOS devices, I would appreciate it if someone could help modify the relevant files such as the *.podspec, and generate the zlib and libzip shared library (.so) files for iOS.

For Android platform #

In Android platform, we ONLY support the following ABI:

  • arm64-v8a: for 64-bit ARM CPU
  • x86_64: for Android emulator on 64-bit Windows

To generate smaller APK file, run the following command:

flutter build apk --target-platform android-arm64

Or generate Android App Bundle (.aab) for uploading Google Play:

flutter build appbundle --target-platform android-arm64

For Linux platform #

In Ubuntu Linux (for example), the following packages need to be installed during development:

sudo apt install libzip-dev
sudo apt install zipcmp
sudo apt install zipmerge
sudo apt install ziptool

For MacOS platform #

Libzip needs to be installed during development:

brew install libzip

Feature list #

  • Compress a folder into a .zip file
  • Extract files from a .zip archive
  • List all file properties inside a .zip archive
  • Read file within a .zip archive
  • Rename a file inside a .zip archive
  • Move a file within a .zip archive
  • Delete a file inside a .zip archive

Multi-thread support #

When you compress an entire folder into a .zip file or extract files from a .zip archive to a specified folder, you can specify the number of threads to speed up the compression or extraction process.

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  native_zip: latest

Easy-to-use Functions #

Compress a folder into a .zip file #

var future = NativeZip.zipDir(
  "D:\\folder_path",
  "D:\\test.zip",
  password: "your-password",    // optional
  compressLevel: 5,  // optional
  threadCount: 8,    // optional
);
await future;

There are some optional arguments:

  • password: set a password to protect .zip archive if necessary.
  • compressLevel: The value ranges from 1 to 9. 1 represents the fastest compression speed but the lowest compression ratio. 9 represents the slowest compression speed but the highest compression ratio. Default value is 5.
  • threadCount: By default, the maximum number of CPU threads will be used.

If you want to display the progress during the operation:

showProgress(future);
await future;

void showProgress(ZipTaskFuture future) {
  var timer = Timer.periodic(const Duration(milliseconds: 500), (_) {
    var progress = future.processedSize / future.totalSize * 100;
    var compressRatio = future.compressedSize / future.processedSize * 100;
    var path = future.nowProcessingFilepath;
    log("progress: $progress%, compress ratio: $compressRatio%, path: $path");
  });
  future.whenComplete(() {
    log("finish");
    timer.cancel();
  });
}

Cancel the operation before finish:

future.cancel();

Extract all files from a .zip archive #

var future = NativeZip.unzipToDir(
  "D:\\test.zip", 
  "D:\\output_folder", 
  password: "password-of-zip",  // optional
  threadCount: 8,               // optional
);

showProgress(future); // to show progress, mentioned above
await future;

There are some optional arguments:

  • password: set password if this .zip file is protected by password. Operation will be failed if password is incorrect.
  • threadCount: By default, the maximum number of CPU threads will be used.

Call showProgress() mentioned above to display progress during operation.

Cancel the operation before finish:

future.cancel();

Zip file operations #

Open zip file #

ZipFile zip = NativeZip.openZipFile(
  "D:\\test.zip", 
  password: "password", // optional
);

For the optional argument password:

  • When you open an existing .zip file, if the .zip file is protected by password, you MUST pass the correct password here; otherwise, the operation will fail.
  • When you create a new .zip file, if you want to protect it with a password, you must provide the password here.

Close zip file #

Don't forget to close the zip file to free resources at last.

zip.close();

Get file list #

To get all files info within zip file:

var entries = zip.getEntries();

To get all files info under directory "flutter/" (recursively) within zip file:

var entries = zip.getEntries(
  path: "flutter/",  // optional, default is "" (root)
  recursive: true, // optional, default is true
);

To get all files info under directory "flutter/" (NO recursively) within zip file:

var entries = zip.getEntries(
  path: "flutter/docs/",  // optional, default is "" (root)
  recursive: false, // optional, default is true
);

NOTE:

  • argument path must be:
    • empty string "" (stands for root)
    • or, a path ends with '/' character
  • all the path argument follow this rule

Print information of returned entries:

for (var e in entries) {
  // e.isDirectory
  // e.path
  // e.modifiedDateTime
  // e.originalSize
  // e.compressedSize

  // Stream<List<int>> stream = e.openRead();
}

Read file content #

Read file content in zip:

Stream<List<int>> content = zip.openRead("docs/README.md");

For example, reading a text file and print it:

String content = await zip
    .openRead("docs/README.md")
    .transform(utf8.decoder)
    .join();
print(content);

Write file content #

Due to technical limitations, there is no method like zip.openWrite(...) available, so writing from a Dart buffer directly into a zip archive is not supported.
Please use the zip.addFiles(...) method described below to add files from the disk into the zip archive.

Rename a file or directory #

Rename directory dirA to dirB: ( )

await zip.renameEntry("prefix/dirA/", "prefix/dirB/");

Rename file fileA.txt to fileB.txt:

await zip.renameEntry("prefix/fileA.txt", "prefix/fileB.txt");

Move one or more file or directory #

For example, move folder flutter/DirA/ and folder flutter/docs/DirB/ and file prefix/fileA.txt to folder targetDirPath/ :

var entries = <String>["flutter/DirA/", "flutter/docs/DirB/", "prefix/fileA.txt"];
var toDirPath = "targetDirPath/";
await zip.moveEntries(entries, toDirPath);

NOTE:

  • all directory path must ends with '/ character
  • or a empty string "" stands for root folder

Call moveEntry to move ONLY ONE file or directory:

await zip.moveEntry("flutter/DirA/", "targetDirPath/");

Delete one or more file or directory #

Remove directory flutter/docs/ and file README.md

var entries = <String>["flutter/docs/", "README.md"];
await zip.removeEntries(entries);

Call removeEntry to remove ONLY ONE file or directory:

await zip.removeEntry("flutter/docs/");

Add files/directories from disk into existing zip archive #

For example, add directory D:\\dirA and file C:\\fileB.txt, into directory targetDirInZip/ in zip archive:

var sourcesInDisk = <String>["D:\\dirA", "C:\\fileB.txt"];
var future = zip.addFiles(
  sourcesInDisk, 
  "targetDirInZip/",
  compressLevel: compressLevel, // optional
  skipTopLevel: skipTopLevel,   // optional
  threadCount: threadCount      // optional
);

showProgress(future); // to show progress, mentioned above
await future;

Refer to NativeZip.zipDir() mentioned above for details.

Cancel the operation before finish:

future.cancel();

Extract files/directories from zip archive to disk #

For example, copy directory flutter/docs/ and file flutter/README.md from zip archive to disk directory D:\\dir:

var sourcesInZip = <String>["flutter/docs/", "flutter/README.md"];
var future = zip.saveFilesTo(
  sourcesInZip, 
  "D:\\dir",
  threadCount: threadCount, // optional
);

showProgress(future); // to show progress, mentioned above
await future;

Use zip.saveTo() instead to copy only ONE directory or file.

Refer to NativeZip.unzipToDir() mentioned above for details.

Cancel the operation before finish:

future.cancel();

Rules for path string #

  • For a directory in disk:
    • path must NOT ends with / or \\
    • e.g. /dirA (Unix)
    • e.g. D:\\dirA (Windows)
  • For a directory in zip:
    • path must NOT starts with /
    • path MUST ends with /
    • e.g. dirA/dirB/
    • special case: empty string "" stands for ROOT directory
  • For a file in zip:
    • path must NOT starts with /
    • path must NOT ends with /
    • e.g. dirA/fileB.txt

Limitations #

  • Due to the limitation of zip format, the following information are ignored whe zipping and unzipping, and we won't support it:
    • All symbolic link files or directories are ignored.
    • The inode information of a hard link file are ignored.
    • Unix file permission information (e.g. -rwxrw-r--) are ignored

Other Packages by Me #

I also develop other Flutter packages that you might find interesting, although they are not related to this one:

  • native_crypto : Fast encryption (AES), and MD5, SHA, HMAC cryptographic functions, using built-in system API, with hardware-acceleration (if OS and device support).
2
likes
160
points
451
downloads

Publisher

unverified uploader

Weekly Downloads

A FFI plugin for fast, easy-to-use, multi-threaded ZIP file operations.

Repository (GitHub)
View/report issues

Topics

#zip #archive #compression #multi-thread #ffi

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

ffi

More

Packages that depend on native_zip

Packages that implement native_zip