我使用 firebase 云存储来存储一些文件,然后,我必须将它们放入 zip 文件中并下载它,我必须ONLY在网络上执行此操作,这就是困难的部分。 我现在这样做:
FloatingActionButton(
child: const Icon(Icons.download),
onPressed: () async {
List<int>? bytes;
webarc.ZipEncoder encoder = webarc.ZipEncoder();
webarc.Archive archive = webarc.Archive();
try {
List<String> links = await Database.formLinks();
for (String link in links) {
String fileName = link.substring(link.lastIndexOf('/') + 1);
http.Response response = await http.get(
Uri.parse(link),
headers: headers,
);
webarc.ArchiveFile file = webarc.ArchiveFile.stream(
fileName,
response.bodyBytes.elementSizeInBytes,
response.bodyBytes.toList(),
);
archive.addFile(file);
}
webarc.OutputStream outputStream = webarc.OutputStream(
byteOrder: webarc.LITTLE_ENDIAN,
);
bytes = encoder.encode(
archive,
level: webarc.Deflate.BEST_COMPRESSION,
modified: DateTime.now(),
output: outputStream,
);
} catch (e) {
print(e);
Fluttertoast.showToast(
msg: 'Errore nel download dello zip.',
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.BOTTOM,
);
return;
}
if (bytes == null) {
Fluttertoast.showToast(
msg: 'Errore nel download dello zip. bytes nulli.',
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.BOTTOM,
);
return;
}
String zipFileName = 'forms.zip';
await FileSaver.instance.saveFile(
zipFileName,
Uint8List.fromList(bytes),
'zip',
mimeType: MimeType.ZIP,
);
Fluttertoast.showToast(
msg: 'Zip downloadato correttamente.',
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.BOTTOM,
);
},
),
一切都很完美,除了我下载了 zip 文件,但 zip 文件是空的。
我尝试以多种不同的方式执行此操作,使用 html 包下载它,锚定并单击 div,但现在我认为该包不起作用,我该怎么做?任何帮助都会被接受,谢谢。
附注 这是database.formLinks函数:
static Future<List<Reference>> getCompiledForms() async =>
(await formsRef.listAll()).items;
static Future<List<String>> formLinks() async {
final List<Reference> forms = await getCompiledForms();
final List<String> links = [];
for (final form in forms) {
String url = await form.getDownloadURL();
links.add(url);
}
return links;
}
这些是我在这些功能中使用的包:
存档:^3.1.2(作为 webarc)
http:^0.13.3(作为http)
文件保存程序:^0.0.10
颤抖吐司:^8.0.7
cloud_firestore:^2.3.0
本周我遇到了类似的问题,并且能够找出问题所在。我正在使用使用anchor.click()方法进行html下载。
Download files as zip 方法将输入作为 String 形式的文件名列表和 Uint8List 形式的文件数据列表。
尝试一下,让我知道这是否适合您!
_downloadFilesAsZIP(context, List<String> filenames, files) {
var encoder = ZipEncoder();
var archive = Archive();
ArchiveFile archiveFiles = ArchiveFile.stream(
filenames[0].toString(),
files[0].lengthInBytes,
files[0],
);
print(archiveFiles);
archive.addFile(archiveFiles);
var outputStream = OutputStream(
byteOrder: LITTLE_ENDIAN,
);
var bytes = encoder.encode(archive,
level: Deflate.BEST_COMPRESSION, output: outputStream);
print(bytes);
downloadFile("out.zip", bytes);
}
downloadFile(String fileName, Uint8List bytes) {
final blob = html.Blob([bytes]);
final url = html.Url.createObjectUrlFromBlob(blob);
final anchor = html.document.createElement('a') as html.AnchorElement
..href = url
..style.display = 'none'
..download = fileName;
html.document.body.children.add(anchor);
// download
anchor.click();
// cleanup
html.document.body.children.remove(anchor);
html.Url.revokeObjectUrl(url);
}
我从 AmateurCoder 获取了不再工作的代码,并对其进行了一些修改,使其在 2024 年可以工作。我还添加了一个小的使用示例。
修改代码
downloadFilesAsZIP({required BuildContext context, required Map<String, InputStreamBase> files, required String zipFileName}) {
var encoder = ZipEncoder();
var archive = Archive();
for (var file in files.entries) {
var archiveFiles = ArchiveFile.stream(
file.key,
file.value.length,
file.value,
);
archive.addFile(archiveFiles);
}
var outputStream = OutputStream(
byteOrder: LITTLE_ENDIAN,
);
var byteList = encoder.encode(archive, level: Deflate.BEST_COMPRESSION, output: outputStream);
if (byteList == null) return;
final Uint8List uint8List = Uint8List.fromList(byteList);
downloadFile(zipFileName, uint8List);
}
downloadFile(String fileName, Uint8List bytes) {
final blob = html.Blob([bytes]);
final url = html.Url.createObjectUrlFromBlob(blob);
final anchor = html.document.createElement('a') as html.AnchorElement
..href = url
..style.display = 'none'
..download = fileName;
html.document.body?.children.add(anchor);
// download
anchor.click();
// cleanup
html.document.body?.children.remove(anchor);
html.Url.revokeObjectUrl(url);
}
使用示例
ElevatedButton(
onPressed: () {
List<int> fileData = utf8.encode('Test');
downloadFilesAsZIP(
context: context,
zipFileName: 'test.zip',
files: {
'test.txt': InputStream(fileData),
},
);
},
child: const Text('Download'),
),