How to Read/Write Text, JSON, and Image Files in Flutter

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello today i'm going to show you how to read and write files in your app using the flutter sdk and a few helpful libraries that can make the process a little bit smoother so before the video i created this app here that really doesn't do much it just has a screen here with a safety txt button select the json button etc okay so we have our buttons here these are custom buttons that can be found under this folder cheater button and cheetah input here okay so for the home screen these buttons don't really do much but now we're going to actually find a way to write files to a txt file and write files to a json file so the first thing i want to do is i'm going to go to the lib folder create a new file called a file manager so this is what i like to do to separate out the different parts of the app so i like to keep the ui separate from the state and the state separate from the business logic okay so the file manager class here will be something like a service class so we'll say class file manager and i want this to actually be a singleton class and you'll see why i want to do that shortly so down here i want to say static file manager and then we'll say underscore instance okay and to create the constructor for that we want to say file manager and you'll see that people use dot internal a lot it doesn't have to be internal you can use whatever you want to here but that's just to come in practice so dot internal underscore instance and then we'll return this instance of the class and down here i'm going to create a factory so we'll say factory file manager and then return underscore instance and then i want to say if this is null then return the internal constructor here so we'll say question mark question mark file manager dot internal okay and i should probably make this underscore just to keep it consistent so underscore underscore so if we don't have the instance of so if we have no instance of this class defined will return a new instance here okay otherwise we'll return this current instance okay and down here i want to create all of the business logic that our app is going to use to read and write different files so first i want to define what the directory path is so i'm going to say future and then i want to return the path so it'll be a string and this will be a getter so i'm going to say underscore directory path and then it'll be asynchronous async and now we want to define the directory that this file will live in so we'll say directory directory equals await and then i want to use the get external storage directory as you can see there's many different options but this one is specific to your application so once your app is removed from the phone all the data that you put inside of here will be deleted which is normally what you want okay so we'll do that and then we want to import the i o here so i think it's dart io yep and down here i want to say return directory dot path and this will return the path from this getter here okay and down here so first we're going to work with the txt here okay so i want to return a future and this would be of type file and this would be a getter so underscore file async again and now i want to define the path for that file i'm going to say final path path equals away you don't have to say final here you could say a string if you want to but um so await underscore then we get the directory path here so underscore directory path and then return a new file with that path so we'll say file and then we'll put the actual string to the path in here so use that path variable here so we say path and then i want to name the file so i'm just going to call it cheetah.txt so if you want it to be a txt file you want to add that extension here okay so this represents the file with this location okay and this name here so whenever we create a file using this it will write it to cheetah.txt okay now to finish up the business logic we can go down here and now i want to create a method called read text file so read text file okay and this will be asynchronous and now i want to create like a default value for the text if that file doesn't exist so i'm going to display the text right here where it says cheetah coding so i'm going to say string and i'll call it file content and then i'll say equals cheetah coding okay so that represents this here now i want to create a new file so we'll say file file equals await and then we use that file that we created up here so we'll point to this file here so underscore file and now i want to check if this file exists first so we go down here and say if i can actually put the await in here too so i'm going to say await and then i'm going to say exist okay so we wait to see if the file exists first if it does we can say file content equals await so we have a lot of awaits in here that's important because these are features so we say await file dot then we have a few different options here we have read here so read you have a read a string sync and read a string we want to say read as string and you'll probably want to wrap this in a try catch too that's really up to you if something does go wrong then your app might crash but we'll put try catching here and then we'll just print that exception here okay and down here i want to actually return that file or that file content i mean so that string here so i will return the file content and then just to make it a little bit more readable i will add the return type here okay so i hope this makes sense um there's libraries that you can use to do this too but i don't know why you would when it's this easy so you can see it's not really much code we just define the file directory and path here then we check to see if that file exists first if it does exist then we just read it here into the string and then we return it so now let's write the last function for that and that is the write function so we can say write text file okay this will be asynchronous to async and for this i want to write something to the file so i think what i want to do is i want to write the current time so i'm going to write a formatted string time so i want to say string text equals and we'll do a if you look in the pub spec here i added a few different packages here that i know i will want to use because i kind of thought about what i wanted to do with this app beforehand so i added the path provider package the provider package the international package i think that's what that stands for and the http package okay i added the intl package for that time format so let's go back here and i'm going to create a date format so date format comes from that package so you could look up here we imported that intl package okay so i want to format this date and i want the format to be i think it's hour minutes seconds and then i want to say dot so we do dot format and then i'm going to get the current time now so i just do date time now so this is a very very easy and clean way to get a string format of the time now okay and down here i want to create a new file like we did above so actually i will just copy this and then down here i want to write the file now so up here we we read it as a string down here i want to write it so i would do await and then i'm going to say file instead of read i want to do write so right as string and then i just want to put that message in here or that that string in here so we'll say text here okay and actually i want to return that to and you'll see why i want to return that in a bit so we'll see return text and then i'll put the return type here and that's it so now we have two very simple functions to read a text file and write the text file and we have our location here in one place so we don't need to worry about putting in the wrong path for one of these two here okay so now we have our file manager service here now i want to read from these so i'm going to go over here and create a new folder and i'm going to call it controller and inside of here i'm going to create a new controller so i'm using a provider you can use whatever you want to you can use get x provider block etc but i just want a place to have my state stored and a place to call the file manager functions okay so we'll say new file i'll call it file controller dot dart so again i'm keeping things separate so we have our ui we have our state and we have our business logic here in the file manager okay class file controller extends if you know provider you know how this works we'll say change notifier and then up here i want to store the text that i want to show in the text field here when the file data loads so i'm going to say string underscore text okay and down here i'll create a getter for that so i'll say string get text return underscore text okay and now i want to create two functions to read and write the text so i will call the file manager from here the singleton from here so we'll say read text async and then i want to set the text to the value that i get back from the read text flaw here so we're reading the text file and setting it to a string here okay i can say underscore text equals await file manager it's a singleton so we'll have the parentheses here and then dot read text file but we also want to notify the ui when it has been set so down here we'll say notify listeners okay and down here we'll have write text async and then we'll read or write the text file and remember that returns a string also so up here we'll say underscore text equals away file manager dot write text file okay in a normal app you might pass some data in here it's the same concept i'm just doing all of the logic inside of here okay and you also might do the logic inside of here too if you're maybe calling like an api or something like that okay and don't forget the notify listeners so we're going to go to the main and we need to add that controller to our main again i'm assuming that you already know how to use provider or you have a general understanding of it okay so up here i'm going to wrap the my app in a multi provider and then i'm going to add the change notifier provider we'll do create we're not going to use the context here and then we'll just set it as the file controller okay and we want to set this as the child and i'm missing a couple things so we need to wrap brackets and this goes inside of here there we go and for this app i'm going to keep it pretty simple i'm going to read all of the data that we want to read from our files instead of our main here so in the build i'm going to say context dot read of type file controller and then i'm going to read the text so this will make sure that every time our app loads up we will read the text whether it exists or not so we'll say retext and we will return the file content so the file content will either be cheat decoding or if we have a existing file it'll be some string inside of the file here okay so it'll never be no in this case and now when we press the button i want to call that function to write the text file down here i'm going to say context dot read file controller and then we're going to write that file so i need to import the provider so copy this into here so now we can actually use that here so we can import the file controller too and now it's pretty simple we can just say write text so in a normal app you'll probably pass in something like user input or something here but i chose to put everything inside of the file manager to make things simpler for the video okay so now we're reading and writing our file so if we load the text in the file i want to show that here okay so up here inside of our text here instead of cheater coding i want to use our contacts here so i want to say context and instead of dot read i want to say dot select so dot select will let us listen for the changing value of the file controller that we specify so we'll say file controller controller and then i want to listen for the controller dot text and that's it so this text will always be either the cheetah coding text or the file text okay so let's reload or restart okay and you can see that we have an error here so let's look at where the error is file manager 16. ah good to know this does not work on ios this only works on android so i tested this on android right before the the video so on ios we have to use something else so we can use get application documents directory okay so let's restart okay and that works on android you're probably going to put in a case to check the platforms yeah so on android i use the get external uh storage directory and on ios you want to use this so you'll do a so you'll check the platform and say if platform is ios use this on android use get external storage directory that's a minor minor uh frustration with this but not a huge do so now we'll press the save to text button and now you can see that the time was put here and the text so every time you press this button it'll put the current time here so you can see hours minutes seconds and this is in a 12 hour time not military time okay so the real test is to restart the app so i'm going to quit and run again and actually i will uh close the app like this first just to make sure that it's actually closed okay and now you can see that the time has been loaded so the time that we saved in the file has been loaded when we restarted the app so that proves that the text was saved to a file and you can see this exception here too data not equal to null so let's put just an empty string here like this here okay and that should get rid of that exception yep there we go so this is the basic procedure that i'm going to be doing for the next two steps that'll be the json objects that we want to save to files and images slash videos so now i will show you to save a json file okay so first let's go to the file manager here and i'm going to create a new file path so down here actually let's copy and paste this down here it will be the same structure here so we'll say underscore json file and then instead of cheater.txt i will say cheetah.json and that's it for the file path so down here i want to create functions for the json file so down here i will say read json file this will be async and this is going to be very similar to what we have up here so i'm actually going to just copy this entire thing here so we have our file content file if the file exists then we read it as a string the only difference is down here instead of the file content we want to decode the json file into a map okay and before i continue with this part i need to create a model that we want to save to the json file so over here let's go create a new folder i call it model and then i'll create a new model here we'll say new file user dot dart and then i'm just going to create a simple user class here so user uh will give it a name so final string name final string and it should be a class final string age and final uh let's do a list here so a list of nick names okay and then we'll create a constructor so user will pass in this dot name this dot age and this dot nicknames so if you worked with flutter for a while then you probably know how to convert from a json object to your model and vice versa but i will show you that real quick um so i want to convert from a json object to a user object so we'll say user and then this will be a name constructor so we'll say user dot from json is pretty common so we'll say map and this will be a string dynamic passing the json here and then i would just have name equals json and we'll just get a name key so name key and then we'll do the age json age and then the nicknames will be json nicknames make sure these are spelled the way you want them to be spelled nicknames and down here i'll create the reverse of that so i'll say map string dynamic and then this will be 2 json and then i'm going to create a json object from our strings here or from our fields here i mean so down here we'll return this object so we'll do name name i think this is pretty standard to do in most apps especially if you're working with an api so back to the file manager so here instead of returning the string file content i want to return a map and then from that map i'm going to convert that map to the user model okay so down here we're going to say json and that can be imported from the convert package so up here you can see we imported the convert here this is a very very handy tool to use um so json and then we can say decode so we pass in the file content here so be careful about doing that you have to make sure that this is a carefully formatted json string or else it won't be converted into the model that you want it to be converted into so once again this is the only difference between the read json file function and the read text file function oh yeah and i forgot to actually use the right file so i'm using the text file which will point to the txt but i want to point to the json file so copy this and put it into here so these two things are the only difference yeah don't forget to point to the right path here okay so now i want to write the json file okay and down here i want to say write json file async you can see a pattern here too i'm just going to create a random user here normally this would come from a api or maybe a database or something so but for this video we're just going to say final user user let's import the user equals user and then i'm just going to pass in some random data actually i'll pass in my my name and age so we'll say julian and then pass in my age 36 and then pass in some nicknames so i've had a few different nicknames here they are so one is jules there's juice and there's like j it could be the letter j um okay so we have our user and now i want to get the json file so we can copy this from up here and now i want to write it as a string so as we did up here i can copy this put it into here instead of the text here now i want to encode the json file so up here we decoded it to get into a map now i want to encode it so we say json dot encode and then you pass in the object so this encodes it as a json string so encode user and that's it so now i want to return the user here and we can add the return values up here too so we can say return type and up here return type okay so now we can go up the chain and this is giving me an error this should be a it here okay so now we can go back up the chain to the controller and now i want to store our user object inside of this controller so we can say user underscore user um and now i want to create a getter for that so we can say user get user return underscore user okay so you can see a pattern here too so import and now i want to create a read and write method for our user so we can say read user these are all async async and now i want to set the user equal to that value so we can say user equals await and actually we don't want to do that yet because we want to convert that to a user first so we have our user dot from constructor here so user.from so i'm going to say user so we could do this in our servers too but this is fine so user dot from json and now i want to await that file manager function dot read json file so since we're saving it in our user as a map string dynamic we can make that the type here too so copy this and go back to the manager so this would be a feature of that type here okay so let's go back to our controller and you can see here so we're converting from a map to our user object okay so i hope that makes sense we're reading the file of contents as a string we're decoding that json string into a map here and we're mapping the variables of that map to our user so we can have a user model that we can pass around in our app to different screens so back to the controller now i want to do notify listeners and down here follow the same pattern we can do write user and now i want to set the user equal to await file manager right json file okay pretty simple and we return that user value here again you might want to do a try catch here just in case but you can kind of see what we're doing we're just creating the user writing it to the file after it's written we just return the same user and then we want to notify listeners okay so you can see how clean this looks already like i like to keep my code very organized when i'm writing the code out the architecture is very very important so let's go back to our home screen now and now i want to actually use that controller function so in our second button here i want to say context.read same process file controller dot write user okay and we're not passing anything in because we're creating the user inside of our service here and let's go to the main and i want to read the user as soon as the app loads too so we'll say context dot read file controller dot read user okay so once again this will set the user in our state so it's readily available whenever we want to access that value so now where do we want to show that user let's go to the home screen and i'm just going to show the user i'll just show the user name in the app bar here so let's go to the app bar and instead of cheater coding if we have a json file there then i want to show that instead so this would be a if else statement here so uh down here let's say context dot select again because we want to listen for that value we can say file controller controller and then if we have a controller dot user so if that is not equal to null because by default it's set to null here so if it's not equal to null then i want to say controller dot user dot name else i want to show that okay hope that makes sense let's do this yeah that looks good okay so if we don't have a user show cheater coding else show the username from the json file that we load it okay so now let's test all of this let's restart the app and we have a exception here probably forgot to save something i probably forgot to save something here controller 23 ah so the issue is this decode here we're trying to decode this this string here if this fails because the file does not exist um so to get rid of this let's put this up here so like so and if we get a exception we'll return null here okay and then back in the controller actually we'll set this equal to something first so we'll say final result equals this and we could say if result is not equal to null then do this so this makes it so if that read fails because our json file does not exist then we can do this from json and set the user else we don't set the user okay and back in the home screen if the user is not set then we'll just show this here okay so let's try this again reload there we go so we say cheater coding because it's false and i'm not using this read json file here hold on let's go back real quick so i need to add a return here too so let's do return okay restart and now let's press the save to json button save and now you can see it changed to julian okay and let's uh restart our app again and see if it still says julian here okay and now you can see that it still says julian here so that proves that we have loaded a user object from a json file that we stored on the device so in a real world app you could uh get some large json file from an api and you can store that json file on your phone and just retrieve it whenever you want to so you don't have to connect to the internet every time you want to retrieve that data okay so if the data doesn't change a lot that might be a good idea to use in your app so the last thing i want to show is how to save an image in flutter okay so we can save an image and delete an image here so let's go to the file manager and i want to create a new function i want to name it right let's say image file and this will be async to async so we're going to use the http client okay so i'm going to say response response equals then we'll await and now we'll get the client object so this class provides you with all the rest calls for your client so say client dot get and now we can pass in the url here so i already have a url that i saved that i want to get i'm going to paste that into here and get rid of these and this won't work because it says that it needs a uri so you have to wrap this in a uri so you could say uri and then we parse that so we say parse so we parse that string into a uri so we can retrieve it from the internet okay put that down here and now comes the tricky part with saving images to a file so when writing an image it's best to use a object called uint8 list so that gives you a byte list for an image or whatever you're trying to save to storage down here i want to say you and 8 there's other ones too but un8 list is the most common one so un8 list and then i want to say bytes equals response dot then you want to say body bytes so that returns a u into 8 list okay so this represents the byte list of the image and down here now we'll have the same things that we had up above we have the file so we have file and then let's call this one i need to create a new location too so up here we have the text file the json file path now we want to create one for the image so this will be future file get and then let's call this image file async and we'll copy in this part and now i want to return a new file and actually let's copy this too and instead of that we'll just call this one uh cheetah underscore image and you could put png or gif or whatever um i usually leave it off if i'm saving it to storage if you're trying to open it in a like a different app or from your file storage uh like a file app then you won't be able to open it if it's not like a proper image extension okay so we have our return image file here so down here this will be underscore image file and now we want to write the bytes to that file so down here we can say await file dot right and instead of s string we do write as bytes so that takes in a list of bytes which is exactly what we have here so we can say right as bytes and pass in the bytes here so passing the bytes and then uh for this actually i want to print this out just so i can show you what it looks like so print out the the file.path and we can also print out the the bytes too so let's do print bytes and then i want to return the bytes so we'll return the bytes here okay and then we can add the return type and while we're here i'm going to add the read part also so now we have read image file okay async so we have our file here let's do file and now i want to create a list of bytes so up here we saw that we got our list of bytes here now i want to make a similar list here so down here you and aid list and then call it by list i guess and now i want to see if this file exists first so like we did up here uh if file exists let's just copy and paste this actually and now i want to set this equal to byte list here and instead of read that string here we say read as bytes so for the text in json we said write as a string and read a string for the image we say read as bytes write as bytes and pass in the u into a list okay so we don't need this json decode thing here okay and that's all for that but we want to return the byte list too so down here let's return by list and add the return type here okay so i know a lot of this video was like just putting stuff in different places but you could see how organized all this stuff is we have all the file paths here and a nice little structure here we have the functions very very specific to what their task is we have read write read write read write okay so back to the controller now we want to have the functions to read and write images but first up here we're returning the un8 list so i want to store that too in the file controller so i want to say you and 8 list and then i will call that image by list and we'll create our getter here so you get a list get and then we'll call it image byte list return image bytes okay and now we create the functions so down here i'm going to say read image sync and i will set the image byte list image byte list to that function to read the image bytes so we'll say equals away file manager dot read image file and then we can say notify listeners okay and now i want to write the image so down here we could say write image sync very similar pattern here equals await file manager dot right image file and notify listeners okay and before i test this uh i might as well work on the fourth button too because it's related to the image let's go to the file manager and down here i'm going to call a function called delete image this one won't have a return type because i don't need to return anything then i can say async and then up here get the image file and this one is going to be very simple i'm going to check to see if it exists first so this one if it does exist i'm going to call file dot delete and that's it and we can do and wait here too okay and that's all i'm going to do for this entire function here okay so back here i'm going to create a new function called delete image sync and then down here i'm going to delete the image and then set the the image by list to no okay i'm going to call file manager dot delete image and then after this is done i'm going to set this to null and do a notify listeners so what i want to do with the images i want to set the new image to this logo here so if we have a image stored in the location that i set then i want to show that here if not i'm going to show the same cheetah coding logo here if we don't have one set i'm going to show the same cheetah coding logo here okay and then when i delete the image i want to set that back to the chi-chi coding logo okay so back to the home screen and the third button i want to set this to write the of the image okay so down here i want to say context dot read file controller and then we can do right image okay and now let's go back up here to the image asset so i only want to show this image asset if the image by list is set to null okay so i want to do a context.select again so context dot select okay so let's do file controller controller and then i want to say if controller.imagebytelist is not equal to null then i want to show the image so doing that is different than this asset so in that case we don't say image.set we say image dot memory because you see here this takes in a uint 8 list and that's what we are storing in our controller so we say image.memory and we pass in that byte list so we say controller dot image byte list and then we can set the height like we do down here too so height 160 160. so if that is not set then we show our logo here okay so this is a good way to see how you can store or how you can load images from different places based on a state variable so down here we also need to create the delete function here too so we say context dot read file controller dot delete image and that's it so now we can go through all this and test it so let's reload so now let's try to save the file so let's press save file see and now you can see we have our pikachu here in the log file you can see here we have a giant array and this is our byte list so you can store a image as a byte list or you can store like a video as a byte list etc so let's go back to the manager and yeah this is our print line here and the file path is this here okay so this is the um on ios that is the application documents directory okay so again you could put that png if you want to we want to load the image first so let's do context dot read file controller and then we want to say read image okay now let's restart and now you can see our image is here okay so this is how you save a image to your local storage on the phone and upload it when the app loads up so one final test let's test the delete image so let's press delete and now you can see it went back to the logo because this is now null so now it goes to this instead and if we do a hot restart you can see that that image is no longer there so that's all i wanted to show for this video um this was a lot to go over but um i hope the way that i wrote the code helps you understand it a little bit better than just looking at the documentation using the controller is a great way to store the actual state of your file data and all of these are structured in a way that is easy to read and easy to edit if you want to edit these so i will upload this entire code base on the github repo the link for that will be in the description okay stay tuned for the next one and happy coding bye [Music]
Info
Channel: The Flutter Factory
Views: 19,350
Rating: undefined out of 5
Keywords: cross-platform app tutorials, cheetah coding, Flutter file storage, Flutter directory, Flutter external storage, How to store images in Flutter, Flutter uint8List
Id: oZNvRd96iIs
Channel Id: undefined
Length: 45min 44sec (2744 seconds)
Published: Wed Jul 28 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.