My main goal is to download a file from a link and then save it to the phone's internal storage so that it'll be accessible through the phone's file manager. I'm currently trying out Dio package by running the example code given in the package's repo. Upon running the program, I ran into a path problem. When I used ./example/flutter.png as the download path, I/flutter (10109): FileSystemException: Cannot open file, path = './example/flutter.png' (OS Error: No such file or directory, errno = 2) shows up. And when I used (await getApplicationDocumentsDirectory()).path which produces a String with the value of: /data/user/0/com.example.downloadexample/app_flutter as the path, no error showed up, but the file wasn't there. I tried different variation of the latter path, but with no success. Can someone help me with this problem?
Many thanks in advance.
I use http package, not the Dio, the code:
Future<String> fetchNetFileToDoc(String url, String filename) async {
final path = await getApplicationDocumentsDirectory();
File docFile = File('$path/$filename');
if(await docFile.exists()){
print( '${docFile.path} exits');
return docFile.path;
}
http.Response response = await http.get(url);
// todo - check status
await docFile.writeAsBytes(response.bodyBytes, flush: true);
return docFile.path;
}
if I invoke this method, like: fetchNetFileToDoc('http://a.com/a.mp3', 'a.mp3')
it shows the same error:
FileSystemException: Cannot open file, path= 'Direcotry: '/data/user/0/com.example.master_lu/app_flutter'/a.mp3' (OS Error: No such file or directory, errno = 2)
But if I use getTemporaryDirectory(), change code to this:
Future<String> fetchNetFileToTemp(String url, String filename) async {
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
File tempFile = File('$tempPath/$filename');
if(await tempFile.exists()){
print( '${tempFile.path} exits');
return tempFile.path;
}
http.Response response = await http.get(url);
// todo - check status
await tempFile.writeAsBytes(response.bodyBytes, flush: true);
return tempFile.path;
}
That's ok, it works with the internal storage. Save the file into the data/user/0/com.example.master_lu/cache/a.mp3
The master_lu is the name of my project.
The latest=> I sovle my problem, await getApplicationDocumentsDirectory return Future<Directory>
so, here is the right code:
Future<String> fetchNetFileToDoc(String url, String filename) async {
final docDir = await getApplicationDocumentsDirectory();
String docPath = docDir.path;
File docFile = File('$docPath/$filename');
if(await docFile.exists()){
print( '${docFile.path} exits');
return docFile.path;
}
http.Response response = await http.get(url);
// todo - check status
await docFile.writeAsBytes(response.bodyBytes, flush: true);
return docFile.path;
}
Related
I am reading a file present on a network drive using dart. I want to return a blank list in case the file does not exist or the network cannot be accessed.
I have tried using try/catch and try/on blocks but I don't seem to be able to handle the exception.
Code
readJSONReport(String filePath) async {
/// If file exists on shared network folder,
/// read it and return the list. Else return blank list
List<dynamic> jsonList = [];
try {
File file = await File(filePath);
if (file.existsSync()) {
jsonList = json.decode(await file.readAsString());
}
} on FileSystemException {
print("File not found");
}
return jsonList;
}
Error Message
Unhandled exception:
FileSystemException: Cannot open file, path = '\\10.0.169.142\Users\Public\shared\reports\merged_report.json' (OS Error: The network path was not found.
, errno = 53)
#0 _File.open.<anonymous closure> (dart:io/file_impl.dart:356:9)
<asynchronous suspension>
Another way to ask the same thing would be:
How to check if a file exists on a network path using dart?
OP Here. Turns out, the exception was being raised from a different part of the code. Adding the code I use now to read a JSON file while checking whether the file exists or not.
import 'dart:io';
readJSONReport(String filePath) async {
/// read report file generated by JSON Reporter
/// if file exists, read it and return the list
/// if file does not exist, return empty list
List<dynamic> jsonList = [];
try {
File file = await File(filePath);
print("Reading $filePath");
if (await file.exists()) {
jsonList = json.decode(await file.readAsString());
} else {
print("File does not exist");
}
} catch (e, stacktrace) {
print("Exception occured: $e stackTrace: $stacktrace");
}
return jsonList;
}
Please note that the JSON I am reading starts as a list (as you can expect from a cucumber-json report).
I am using this code and it works fine in simulator as I am getting a location and can get pdf file from there
async createPDF() {
let options = {
html: '<h1>PDF TEST</h1>',
fileName: 'test',
directory: 'Documents',
};
let file = await RNHTMLtoPDF.convert(options)
// console.log(file.filePath);
alert(file.filePath);
}
But the above code problem in the real iOS mobile as it is saving the pdf file somewhere. I don’t know where but I am not able to see that file in my mobile. So can anyone tell me how can I save my file in the downloads or documents in the iOS . So that I can see the downloaded file.
Found the answer to convert file in base64 string
You can solve this issue by using base64 as the following:
let options = {
html:
`
<h2 style="text-align: center">${'Some text and dynamic value'}</h2>
`,
fileName: 'TestingPDF',
directory: 'Documents',
base64: true
};
let file = await RNHTMLtoPDF.convert(options);
You shoud use 'react-native-file-access' to copy the file and move it to Downloads directory, so let's install it by: npm i react-native-file-access --save
Lets copy the file to the Downloads directory by the following:
const fileName = 'PMA_CurrentBalanceFile.pdf'; //whatever you want to call your file
const filePath = `${Dirs.DocumentDir}/${fileName}`;
const base64Data = file.base64; //our base64 encode file which done by RNHTMLtoPDF;
Then write the following code to do your job:
if (Platform.OS === 'android') {
const permissionGranted = await permissionWriteExternalStorage();
if (permissionGranted) {
await FileSystem.writeFile(filePath, base64Data, 'base64');
if (!FileSystem.exists(filePath)) return;// check to see if our filePath was created
await FileSystem.cpExternal(filePath, fileName,'downloads');// copies our file to the downloads folder/directory
// file should now be visible in the downloads folder
ToastAndroid.show("", "One File Downloaded", ToastAndroid.SHORT);
}
return;
}
if (Platform.OS === 'ios') {
// IOS version
await FileSystem.writeFile(filePath, base64Data, 'base64');
Alert.alert('', 'One File Downloaded');
}
I am working on a wallpaper app in Flutter & Dart. Currently I'm working on the set wallpaper button where I need to check if the wallpaper file exists, download it if need to and then change the wallpaper.
This is what I have right now and I think I've done it right, please note that I'm and Android Java Developer with only about 6 months of experience so I am beyond the basics in Dart too but not too good.
DOWNLOAD WALLPAPER FUNCTION
static Future<int> downloadWallpaperFile(int wallpaperID,
{String path}) async {
///Prepare a url for downloading the wallpaper using the getWallpaperURL method and passing in fullSizedWallpaper string constant
String url = getWallpaperURL(WallpaperSize.fullWallpaper, wallpaperID);
///Log output
print('CallingDownloadWallpaper : ' + url);
///Visual Feedback
wallpaperDetailsPageScaffoldGlobalKey.currentState.showSnackBar(
new SnackBar(content: new Text('Starting Wallpaper Download...')));
///Start downloading the wallpaper file from the url
var data = http.readBytes(url);
///After download is completed
data.then((buffer) async {
///If filePath is not passed in as parameter
if (path == null) {
///Use getPathForWallpaperFile to get a path for a wallpaper file
path = await getPathForWallpaperFile(url);
}
///Create a new file at the path, the path also includes the name of the file which is the id of the wallpaper
File newFile = new File(path);
///Get write access to the newly created wallpaper file
RandomAccessFile rf = newFile.openSync(mode: FileMode.write);
///Write the downloaded data to the file synchronously
rf.writeFromSync(buffer);
///Save the file to the disk synchronously
rf.flushSync();
///Close access to file synchronously
rf.closeSync();
///Log output
print('DownloadWallpaperResult : Complete');
///Visual Feedback
wallpaperDetailsPageScaffoldGlobalKey.currentState.showSnackBar(
new SnackBar(content: new Text('Wallpaper Download Complete')));
});
return 0;
}
SET WALLPAPER FUNCTION
static setWallpaper(int wallpaperID) async {
///Prepare variables for setting wallpaper and download the wallpaper as well (if needed)
String url = getWallpaperURL(WallpaperSize.fullWallpaper, wallpaperID);
String path = await getPathForWallpaperFile(url);
bool fileExists = checkIfFileExists(path);
///If wallpaper file does not exist then download it
if (fileExists == false) {
///Download wallpaper then change wallpaper
await downloadWallpaperFile(wallpaperID, path: path).then((result) {
///Check if download was successful
if (result == 0) {
///Change wallpaper
AndroidInterface.setWallpaper(path);
}
});
} else {
///Wallpaper already downloaded
///Change wallpaper
AndroidInterface.setWallpaper(path);
}
}
The problem is that you are using then, which is non-blocking (basically the old way to use Futures without await).
Instead, use await:
static Future<int> downloadWallpaperFile(int wallpaperID, {String path}) async {
// ...
//Start downloading the wallpaper file from the url
final buffer = await http.readBytes(url);
//After download is completed
//If filePath is not passed in as parameter
if (path == null) {
//Use getPathForWallpaperFile to get a path for a wallpaper file
path = await getPathForWallpaperFile(url);
}
// ...
return 0;
}
Btw, /// is reserved for documentation on classes and fields, use // for in-method comments!
I'm also not sure if it is a good idea to use synchronous io actions. That will probably block the UI of the app, it would be better to use the async io api (again with await).
I would like to know how can a server side application receive a file (via POST) and then print its contents on the server side.
The most "up to date" related question here was this one: Dart how to upload image
But it is not working anymore (Uncaught Error: type 'String' is not a subtype of type 'HttpBodyFileUpload' of 'fileUploaded').
EDIT:
This is how I send the file (this method is working fine):
import 'dart:html';
import 'dart:async';
HttpRequest request = new HttpRequest();
final _HOST = "127.0.0.1", _PORT = 8123;
Future sendFile(File file) {
var completer = new Completer(); // No need for a Completer. It will be removed.
Uri uri = new Uri(host: _HOST, port: _PORT);
request.open("POST", uri.toString());
var filename = file.name;
final FormData formData = new FormData();
formData.append('file', filename);
request.onLoadEnd.listen((_) {
completer.complete(request.response);
});
request.send(formData);
return completer.future;
}
The server side (I'm stuck here):
void _handlePost(HttpRequest req) {
HttpBodyHandler.processRequest(req).then((body) {
HttpBodyFileUpload fileUploaded = body.body['file'];
print(fileUploaded.content);
});
}
You are appending the filename instead of the Blob (File) to your FormData object. In Dart it looks like there is a special function for appending blobs called appendBlob(name, blob, [filename]).
I need to post a PDF file to a remote REST API, and I can't for the life of me figure it out. No matter what I do, the server responds that I have not yet associated an object with the file parameter. Let's say that I have a PDF called test.pdf. This is what I've been doing so far:
// Using an HttpClientRequest named req
req.headers.contentType = new ContentType('application', 'x-www-form-urlencoded');
StringBuffer sb = new StringBuffer();
String fileData = new File('Test.pdf').readAsStringSync();
sb.write('file=$fileData');
req.write(sb.toString());
return req.close();
Thus far, I've tried virtually every combination and encoding of the data that I write() to the request, but to no avail. I've tried sending it as codeUnits, I've tried encoding it using a UTF8.encode, I've tried encoding it using a Latin1Codec, everything. I'm stumped.
Any help would be greatly appreciated.
You can use MultipartRequest from the http package :
var uri = Uri.parse("http://pub.dartlang.org/packages/create");
var request = new http.MultipartRequest("POST", url);
request.fields['user'] = 'john#doe.com';
request.files.add(new http.MultipartFile.fromFile(
'package',
new File('build/package.tar.gz'),
contentType: new ContentType('application', 'x-tar'));
request.send().then((response) {
if (response.statusCode == 200) print("Uploaded!");
});
Try using the multipart/form-data header rather than x-www-form-urlencoded. This should be used for binary data, also can you show your full req request?
void uploadFile(File file) async {
// string to uri
var uri = Uri.parse("enter here upload URL");
// create multipart request
var request = new http.MultipartRequest("POST", uri);
// if you need more parameters to parse, add those like this. i added "user_id". here this "user_id" is a key of the API request
request.fields["user_id"] = "text";
// multipart that takes file.. here this "idDocumentOne_1" is a key of the API request
MultipartFile multipartFile = await http.MultipartFile.fromPath(
'idDocumentOne_1',
file.path
);
// add file to multipart
request.files.add(multipartFile);
// send request to upload file
await request.send().then((response) async {
// listen for response
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}).catchError((e) {
print(e);
});
}
I used file picker to pick file.
Here is the codes for pick file.
Future getPdfAndUpload(int position) async {
File file = await FilePicker.getFile(
type: FileType.custom,
allowedExtensions: ['pdf','docx'],
);
if(file != null) {
setState(() {
file1 = file; //file1 is a global variable which i created
});
}
}
here file_picker flutter library.