Files are empty after downloading zip from assets flutter - flutter

I have a file and folder structure like
Folder
subfolder x
file_x.txt
file_y.txt
....
subfolder y
file_x.txt
file_y.txt
....
subfolder n
I created zip of complete structure in ubuntu and paste that zip in assets folder of flutter project, added assets in pubspecc.yaml
Now I want to open asset zip add new generated file and download complete zip For this i am using archive package. code to load asset add new file and download is as
downloadZip() async {
/// this function open zip template from assets and add custom file in zip
/// and then download whole zip
String newFileString = '...';
final zipEncoder = ZipEncoder();
List<int> utf8encodedData = utf8.encode(newFileString); // newFileString is content of new file to be added
ArchiveFile newFile =
ArchiveFile("file", utf8encodedData.length, utf8encodedData);
DefaultAssetBundle.of(Get.context!)
.load("files/file.zip")
.then((ByteData value) {
Uint8List wzzip =
value.buffer.asUint8List(value.offsetInBytes, value.lengthInBytes);
InputStream inputFileStream = InputStream(wzzip);
final archive = ZipDecoder().decodeBuffer(inputFileStream);
archive.addFile(newFile);
final encodedFile = zipEncoder.encode(archive);
String content = base64Encode(encodedFile!);
html.AnchorElement(
href:
"data:application/octet-stream;charset=utf-16le;base64,$content")
..setAttribute("download", "project.zip")
..click();
inputFileStream.close();
});
}
Problem: In downloaded zip, folder structure is perfect but all files are empty except newFile that i added

Related

How to create a Button that allow user to download a specific file Flutter

I create a flutter app and I have this one CSV file that used as a template for user. I want to provide a Button that allow user to download this CSV file, so they can use it to have CSV file that already have our template.
The problem is I don't know if the best way is to first store the file online and get the url and use it on the flutter downloader URL or keep it in the local code asset and refer to that file when user tap the download template button. Currently I'm applying the second option and it doesn't work (I don't know if this option is possible or not), the download always fail. I'm using flutter_downloader package.
How to fix this ?
Here's my code, Is something wrong with my code ?
/// Check if the file exist or not
if (await File(externalDir!.path + "/" + fileName).exists()) {
OpenFilex.open(externalDir!.path + "/" + fileName);
} else {
/// Download the file if it doesn't exist in the user's device
final String localPath = (await getApplicationDocumentsDirectory()).path;
/// Dummy file name I want use (it exist in my asset dir"
const String fileName = 'add.png';
final data = await rootBundle.load('assets/logo/add.png');
final bytes = data.buffer.asUint8List();
final File file = File('$localPath/$fileName');
await file.writeAsBytes(bytes);
/// Download the file
final taskId = await FlutterDownloader.enqueue(
url: '',
savedDir: localPath,
fileName: fileName,
showNotification: true,
openFileFromNotification: true,
);
}
To load a file from the AppBundle and then save it to the users phone, do the following:
Put the file in assets/filename.csv and declare it in your pubspec like this:
flutter:
assets:
- assets/filename.csv
Load the file in your code:
import 'package:flutter/services.dart' show ByteData, rootBundle;
(...)
var data = (await rootBundle.load('assets/filename.csv)).buffer.asInt8List();
Save the data to a file (you need the path-provider package if you want to copy the exact code):
import 'package:path_provider/path_provider.dart' as pp;
(...)
var path = (await pp.getApplicationDocumentsDirectory()).path;
var file = File('$path/filename.csv');
await file.writeAsBytes(data, flush: true);
Edit: As Stephan correctly pointed out, if you want to store the file in the downloads folder, you will find additional information about that here. Thank you Stephan!

How to save File in Downloads folder in flutter?

In my flutter application I can create a pdf file, then I want to save it in Download folder.
I'm trying to achieve this goal with path_provider package, but I can't.
This is the sample code from flutter's cookbook, If I use it I don't get any error, but I don't find the file either.
final directory = await getApplicationDocumentsDirectory();
File file2 = File("${directory.path}/test.txt");
await file2.writeAsString('TEST ONE');
What's the correct way to do it?
To find the correct path please use ext_storage.
You will need this permission
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
on Android 10 you need this in your manifest
<application
android:requestLegacyExternalStorage="true"
on Android 11 use this instead
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
Remember to ask for them using permission_handler
I leave you my code:
static Future saveInStorage(
String fileName, File file, String extension) async {
await _checkPermission();
String _localPath = (await ExtStorage.getExternalStoragePublicDirectory(
ExtStorage.DIRECTORY_DOWNLOADS))!;
String filePath =
_localPath + "/" + fileName.trim() + "_" + Uuid().v4() + extension;
File fileDef = File(filePath);
await fileDef.create(recursive: true);
Uint8List bytes = await file.readAsBytes();
await fileDef.writeAsBytes(bytes);
}
Android 11 changed a lot of things with its emphasis on scoped storage. Although /storage/emulated/0/Android/data/com.my.app/files is one of the directory paths given by the path_provider pkg, you won't be able to see files saved in /storage/emulated/0/Android/data/com.my.app/files just using any run-of-the-mill file application (Google Files, Samsung My Files, etc.).
A way to get around this (although it only works on Android) is to specify the "general" downloads folder as shown below.
Directory generalDownloadDir = Directory('/storage/emulated/0/Download');
if you write whatever file you are trying to save to that directory, it will show up in the Downloads folder in any standard file manager application, rather than just the application-specific directory that the path_provider pkg provides.
Below is some test code from an app I'm building where I save a user-generated QR code to the user's device. Just for more clarity.
//this code "wraps" the qr widget into an image format
RenderRepaintBoundary boundary = key.currentContext!
.findRenderObject() as RenderRepaintBoundary;
//captures qr image
var image = await boundary.toImage();
String qrName = qrTextController.text;
ByteData? byteData =
await image.toByteData(format: ImageByteFormat.png);
Uint8List pngBytes = byteData!.buffer.asUint8List();
//general downloads folder (accessible by files app) ANDROID ONLY
Directory generalDownloadDir = Directory('/storage/emulated/0/Download'); //! THIS WORKS for android only !!!!!!
//qr image file saved to general downloads folder
File qrJpg = await File('${generalDownloadDir.path}/$qrName.jpg').create();
await qrJpg.writeAsBytes(pngBytes);
Fluttertoast.showToast(msg: ' $qrName QR code was downloaded to ' + generalDownloadDir.path.toString(), gravity: ToastGravity.TOP);
You want getExternalStorageDirectories. You can pass a parameter to specify the downloads specifically:
final directory = (await getExternalStorageDirectories(type: StorageDirectory.downloads)).first!;
File file2 = File("${directory.path}/test.txt");
await file2.writeAsString('TEST ONE');
If you're using null safety you don't need the bang operator:
final directory = (await getExternalStorageDirectories(type: StorageDirectory.downloads)).first;
File file2 = File("${directory.path}/test.txt");
await file2.writeAsString('TEST ONE');
For downloading file in Downloads folder, here are examples:
// Save multiple files
DocumentFileSave.saveMultipleFiles([textBytes, textBytes2], ["text1.txt", "text2.txt"], ["text/plain", "text/plain"]);
//Save single text file
DocumentFileSave.saveFile(textBytes, "my_sample_file.txt", "text/plain");
//Save single pdf file
DocumentFileSave.saveFile(pdfBytes, "my_sample_file.pdf", "appliation/pdf");
//Save single image file
DocumentFileSave.saveFile(imageJPGBytes, "my_sample_file.jpg", "image/jpeg");
More details of library here:
https://pub.dev/packages/document_file_save_plus

How can we delete files inside certain directory flutter?

I want to delete files from any folders of android device using flutter programatically. Is there any way to delete files created as in the code. I downloaded files using dio. and want to delete the files downloaded like this.
var dir = await getExternalStorageDirectory(); await dio.download(fileURL, "${dir.path}/books/$fileName.pdf",
If you want to delete the file after a button pressed, this is what I suggest:
onPressed: () async {
Directory dir = await getExternalStorageDirectory();
final targetFile = Directory("${dir.path}/books/$fileName.pdf");
if(targetFile.existsSync()) {
targetFile.deleteSync(recursive: true);
}
}

Locate path of assets files in flutter app

I am using a package (Starflut) that needs to use a file which I store in assets.
I first add this file to the pubspec.yaml:
assets:
- my_folder/my_file.py
I have then been trying to find this file while running the app, but it is in none of the following directories or any of its subfolders:
/data/user/0/com.example.my_app
/data/data/com.example.my_app
import 'package:path_provider/path_provider.dart';
import 'dart:io';
...
var aux=Directory("/data/user/0/com.example.my_app");
//var aux=Directory("/data/data/com.example.my_app/files");
var files = aux.listSync(recursive:true).toList();
print(files[2]);
for(var i=0; i<files.length; i++){
print(files[i]);
}
And the following code returns the paths below:
Directory tempDir = await getTemporaryDirectory(); // /data/user/0/com.example.my_app/cache
Directory appDocDir = await getApplicationDocumentsDirectory(); // /data/user/0/com.example.my_app/app_flutter
How can I locate the assets/my_file.py so that I can use it from the package (starflut)?
Thanks
Since your asset is packed with application you will have to copy the file from rootBundle to temp directory or your desired location. You can check out this medium post on how to read asset file and write to app path.
Hope this helps.

Flutter how to specify file path in asset folder

I have a sound file in asset folder and I can check if it exist using code like below:
if (FileSystemEntity.typeSync(
'/Users/admin/Library/Developer/CoreSimulator/Devices/AC8BED2E-4EF1-4777-A399-EBD52E38B5C7/data/Containers/Data/Application/1390EE2C-A5D8-46E0-A414-AAC2B83CD20C/Library/Caches/sounds/3/unbeaten.m4a') !=
FileSystemEntityType.notFound) {
print('file is found');
} else {
print('not found');
}
As you can see I need to use the absolute path. Is there a way to check if the file is in the asset folder using path like 'assets/sounds/3/unbeaten.m4a' without the need to specify the whole path?
As was mentioned by #frank06, by using path_provider, I am able to check if a file is in asset folder or not by using the following code. But this works for iOS only and I am still trying to find a solution for Android. Notice the need to add /Library and /Caches for iOS. For Android, it seems that I can't see the path unlike that of iOS.
I would appreciate it if anyone could provide me some info for that of Android. The appDir looks like this for Android - /data/user/0/com.learnchn.alsospeak/app_flutter/
directory = await getApplicationDocumentsDirectory();
var parent = directory.parent;
var directoryPath = directory.path;
var parentPath = parent.path;
String testString = 'sounds/3/unbeaten.m4a';
parentPath = parentPath + '/Library' '/Caches/' '$testString';