extractFileToDisk function
Extracts the archive at inputPath into the directory outputPath.
The archive may be a .zip, .tar, or a tar compressed as .tar.gz,
.tgz, .tar.bz2, .tbz, .tar.xz, .txz, .tar.zst or .tzst.
A compressed tar is decompressed as it is read and every entry written out as it is reached, so no more than a few megabytes of it are in memory at a time and no temp file is needed.
callback is called for each entry once it has been written. For a
compressed tar the entry's content has gone by then and cannot be read
from the entry; it is in the file on disk.
bufferSize is the size of the write buffer for each extracted file, and
password decrypts an encrypted zip.
maxSize limits the total size of the files written, which a small
compressed archive can otherwise make as large as it likes. An entry that
would take it past that throws an ArchiveException before it is
written. A zip entry is never decoded past the size the archive gives for
it.
Entries are kept inside outputPath as extractArchiveToDiskSync
describes, and an entry whose content fails to decode throws.
Implementation
Future<void> extractFileToDisk(String inputPath, String outputPath,
{String? password,
int? bufferSize,
ArchiveCallback? callback,
int? maxSize}) async {
const String extensionMsg =
'.tar.gz, .tgz, .tar.bz2, .tbz, .tar.xz, .txz, .tar.zst, .tzst, .tar '
'or .zip';
// get the extension of the input file with up to 2 components
// e.g. for file.tar.gz, it will return '.tar.gz'
final archiveExt = getInputExtension(inputPath);
if (archiveExt.isEmpty) {
throw ArgumentError.value(
inputPath,
'inputPath',
'No file extension detected, must end with $extensionMsg',
);
}
if (archiveExt != '.zip' && !_tarExtensions.contains(archiveExt)) {
throw ArgumentError.value(inputPath, 'inputPath', 'Must end $extensionMsg');
}
final writer = EntryWriter(outputPath,
bufferSize: bufferSize, maxSize: maxSize, setPermissions: true);
final file = InputFileStream(inputPath);
try {
if (archiveExt == '.zip') {
final archive = ZipDecoder()
.decodeStream(file, password: password, callback: callback);
for (final entry in archive) {
writer.write(entry);
}
await archive.clear();
} else {
final input = tarStreamFor(archiveExt, file)!;
// Each entry is written as the decoder reaches it, which is the only
// time its content is at hand when the tar is being decompressed on the
// way in.
try {
TarDecoder().decodeStream(input, keepEntries: false, callback: (entry) {
writer.write(entry);
callback?.call(entry);
});
} finally {
await input.close();
}
}
writer.finish();
} finally {
await file.close();
}
}