How return bool from write on file - flutter

Am using this for write file on phone
Future<File> writeData(data) async {
final file = await _localFile;
return file.writeAsString(data);
}
how can i know if it write successfully on file ? like is there a way to return a bool value when i write on file to know it write successfully ?

Failures in file writing will be errors or exceptions. You could catch them all and return false in that case and otherwise true.
Future<bool> writeData(data) async {
try {
final file = await _localFile;
file.writeAsString(data);
return true;
catch (_) {
return false;
}
}
Personal opinion ahead:
It would be wiser to handle those errors properly instead of returning a boolean though.

Related

Firebase: How do I write to Realtime Database only if the write to Cloud Storage was successful?

The first function will write to Firebase Cloud Storage and if there are no errors, I want to write to Realtime Database. Both of these are "fire and forget" functions, but I only want to run the second one if the first one successfully uploaded the file to Cloud Storage.
void sendFile(ChatData file, String filepath, String filename) async {
saveToCloudStorage(filepath, filename);
//If the aformentioned function was successful, run the next one
saveToRTDB(file);
}
void saveToCloudStorage(String filepath, String filename) async {
_firebaseStoragePath = MyAppStorageDir + filename;
File file = File(filepath);
try {
await _firebaseStorage
.ref(_firebaseStoragePath)
.putFile(file);
} catch (e) {
}
}
void saveToRTDB(ChatData file) async {
_messagesRef.push().set(file.toJson());
}
Since your saveToCloudStorage swallows any exceptions that are raised, there is no way for the caller to determine whether the call succeeded or failed.
If you don't want to expose what error might have happened, you can return an (async) boolean:
Future<bool> saveToCloudStorage(String filepath, String filename) async {
_firebaseStoragePath = MyAppStorageDir + filename;
File file = File(filepath);
try {
await _firebaseStorage
.ref(_firebaseStoragePath)
.putFile(file);
} catch (e) {
return false;
}
return true;
}
And then in the caller:
saveToCloudStorage(filepath, filename).then(() {
saveToRTDB(file);
})

read file returns null Flutter

I have a page that writes a color on file, called "colors.txt".Then the page is closed, when it will be opened again this file will be read and its content (String) printed on the screen.
This is the class that handles reads and writes :
class Pathfinder {
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/colors.txt');
}
Future<File> writeColor(String color) async {
final file = await _localFile;
// Write the file
return file.writeAsString('$color');
}
Future<String> readColor() async {
try {
final file = await _localFile;
// Read the file
final contents = await file.readAsString();
return contents;
} catch (e) {
// If encountering an error, return 0
return "Error while reading colors";
}
}
}
Before page closure, the color has been saved with writeColor, we just need to read the file and print its content.
And this is how I read the color :
void initState() {
super.initState();
String colorRead;
() async {
pf = new Pathfinder();
colorRead = await pf.readColor();
}();
print("Color in initState: " + colorRead.toString());
}
The problem is that colorRead is always null. I already tried .then() and .whenCompleted() but nothing changed.
So my doubt is :
Am I not waiting read operation in right way or the file, for some reasons, is deleted when page is closed?
I think that if file wouldn't exists then readColor should throw an error.
EDIT : How writeColor is called :
Color bannerColor;
//some code
await pf.writeColor(bannerColor.value.toRadixString(16));
void initState() {
super.initState();
String colorRead;
() async {
pf = new Pathfinder();
colorRead = await pf.readColor();
}();
print("Color in initState: " + colorRead.toString()); /// << this will execute before the async code in the function is executed
}
It's null because of how async/await works. The print statement is going to be called before the anonymous async function finishes executing. If you print in inside the function you should see the color if everything else is working correctly.

Flutter user data taking up a lot of space

My flutter app user data takes up a lot of space. I'm currently using the following code to save the user data
class FileUtil {
static Future<String> get getFilePath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
static Future<File> get getFile async {
final path = await getFilePath;
return File('$path/user.txt');
}
static Future<File> saveToFile(String data) async {
final file = await getFile;
return file.writeAsString(data);
}
static Future readFromFile() async {
try {
final file = await getFile;
String fileContents = await file.readAsString();
log(fileContents);
return json.decode(fileContents);
} catch (e) {
return "";
}
}
String formatData() {
String formattedString;
Map x = {};
x['a'] = a;
// other variables
formattedString = json.encode(x);
return formattedString;
}
void saveData() async {
try {
await saveToFile(formatData());
//print('DATA SAVED');
} catch (e) {
//print('Could not save data due to: $e');
}
}
}
Whenever the user interacts with something in the app that needs to be saved, I run saveData(). This happens quite often in my app. However, after using the app for a while, the user data can jump to a few hundred MB. I've used a JSON calculator to estimate the space of the formatData() output string and it's much less than 1MB. What should I do to minimise user data?

How to resolve future in dart?

I need to read and write files on Flutter.
Write works, but read not or I think it doesn't because the terminal output is flutter: Instance of 'Future<String>'.
What does it means?
This is the code :
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/hello.txt');
}
Future<File> writeHello() async {
final file = await _localFile;
// Write the file.
return file.writeAsString('HelloWorld');
}
Future<String> readHello() async {
try {
final file = await _localFile;
// Read the file.
return await file.readAsString();
} catch (e) {
// If encountering an error, return 0.
return "Can't read";
}
}
.
.
.
writeHello();
print(readHello());
Future<String> is of type Future hence you need to resolve the future, You can either await before printing or use .then() to resolve the Future.
Using await
String data = await readHello();
print(data);
Using .then()
readHello().then((data){ //resolve the future and then print data
print(data);
});
Note: There is no need to add extra "await" here on line 2 as you already are awaiting at line 1:
Future<String> readHello() async {
try {
final file = await _localFile; //Line 1
// Read the file.
return await file.readAsString(); //Line 2
} catch (e) {
// If encountering an error, return 0.
return "Can't read";
}
}
Now I got it, I understood what you said me thank you!
I created a new function that mix write and read.
The problem is that I called async functions in my program body where I can't use await , I should call them in other async functions to handle them in the right way.
I solved with this :
void _RWHello(String text) async {
writeHello();
print(await readHello());
}
.
.
.
_RWHello("HelloWorld");

Call async functions in build method flutter

I need to get the text wrote inside a ".txt" file, save it in a variable and give it to a Text, inside a TextField.
The idea is to write the user input in a ".txt" file so he can read what he wrote when needed on the TextField.
All works, when I read the file it takes the right content but when I store it in a variable to use it Text(var_name...) well what I read on the screen is "Instance of 'Future'".
I know this problem comes from a bad handling of async and future but I would like to really understand why this isn't working.
This is my code :
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localBio async {
final path = await _localPath;
print(path);
return File('$path/bio.txt');
}
Future<File> _write(String text, String filename) async {
final file = await _localBio;
// Write the file.
return file.writeAsString(text);
}
Future<String> _read() async {
try {
final file = await _localBio;
String body = await file.readAsString();
// Read the file.
return body;
} catch (e) {
// If encountering an error, return 0.
return "Can't read";
}
}
Future<String>_MyRead() async {
String read_ = await _read();
print(read_);
return read_;
}
Please write a full answer, I tried a lots of video, forums...Don't just tell me to do var str= _MyRead().then((value) => value);
Maybe it can be the answer but please write 2 more lines because I want to understand why this isn't working.
I took the code from dev official documentation.
You are using an asynchronous value in a rendering process (the build function of a stateful/stateless widget) which is synchronous. You can't just put a Future of String into a place of a String. It won't work. Why? Because it is of a different type, and you need special methods to convert a variable from one type to another.
In this case, you might want to transform this Future into a String asynchronously during the build process. You can use a FutureBuilder for that.
return FutureBuilder<String>(
future: _myRead,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data);
} else {
return Text('awaiting the future');
}
},
);
If you don't transform this Future into a String to be rendered, it will just be an Instance of Future.
you should use a FutureBuilder if you wanna render something that takes time (asynchronous)
FutureBuilder(
future:_myRead,
builder: (ctx,snapshot) {
if(snapshot.connectionState == connectionState.waiting) {
return // your waiting Widget Ex: CircularLoadingIndicator();
} else if (snapshot.hasData) {
return Text(snapshot.data.toString()); // toString() is just to be safe
} else { //probably an error occured
return Text('Something went wrong ...');
}