How to save images from assets to the internal storage in flutter?

6,193

Solution 1

You are trying to create a file object in a path that doesn't exist. You're using your asset path, the path relative to the root of your Flutter project. However, this path doesn't exist in the device's documents folder, so the file can't be created there. The file also doesn't exist in the assets folder because you're prepending the documents path.

To fix your issue, you should pass assetName to rootBundle.load(), without the documents path and open the File() somewhere like $documentPath/foo.jpg

Edit: To create the file you still have to call File.create, so you need to run:

final file = await File('$documentPath/images/foo.jpg').create(recursive: true);

Solution 2

For future reference, this is just to update the solution of @Biplove which really helped me a lot as a newbie...

Future<File> getImageFileFromAssets(String unique, String filename) async {
  ByteData byteData = await rootBundle.load(assets/filename));

  // this creates the file image
  File file = await File('$imagesAppDirectory/$filename').create(recursive: true); 

  // copies data byte by byte
  await file.writeAsBytes(byteData.buffer.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
  
  return file;
}

Thanks.

Share:
6,193
Biplove Lamichhane
Author by

Biplove Lamichhane

Hello!!! Thank you for visiting my profile. If I am of any help to you, it's my pleasure.

Updated on December 23, 2022

Comments

  • Biplove Lamichhane
    Biplove Lamichhane over 1 year

    I am trying to save the image from assets to internal storage. But, I could not load the image from assets to file. Here is what I have done:

    onTap: () async {
      
      final String documentPath = (await getApplicationDocumentsDirectory()).path;
      String imgPath = (galleryItems[currentIndex].assetName).substring(7);
      File image = await getImageFileFromAssets(imgPath);
    
      print(image.path);
    }
    

    I used substring(7) to eliminate assets/ as, my assetName comes as assets/images/foo.jpg.

    Future<File> getImageFileFromAssets(String path) async {
      final byteData = await rootBundle.load('assets/$path');
    
      final file =
          await File('${(await getApplicationDocumentsDirectory()).path}/$path')
              .create(recursive: true);
      await file.writeAsBytes(byteData.buffer
          .asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
    
      return file;
    }
    

    After I get image, I don't know how to proceed forward to create a directory with my name in internal storage. And, copy file there.

    *Note:- I have editted the post, as some basic mistakes were pointed out.

    Update

    Here is what I came up with. And it saves image in the /storage/emulated/0/Android/data/com.example.my_project/files/Pics/foo.jpg path.

    File image = await getImageFileFromAssets(imgPath);
    
    final extDir = await getExternalStorageDirectory();
    
    // Path of file
    final myImagePath = '${extDir.path}/Pics';
    
    // Create directory inside where file will be saved
    await new Directory(myImagePath).create();
    
    // File copied to ext directory.
    File newImage =
        await image.copy("$myImagePath/${basename(imgPath)}");
    
    print(newImage.path);
    

    Here are some links that really helped me:

    Special thanks to @David for the help. Please see comments to understand full scene if you are here to solve your similar problem.

    So, I am accepting the answer from @David.

    • Yadu
      Yadu over 3 years
      now the error must have changed? please post it
    • Biplove Lamichhane
      Biplove Lamichhane over 3 years
      No, now there is not any error. What error are you expecting??? It throws exception FileSystemException: Cannot open file, path = '/data/user/0/com.example.pig_salang/app_flutter/images/foo.‌​jpg' (OS Error: No such file or directory, errno = 2) if I remove .create(recursive: true).
    • Yadu
      Yadu over 3 years
      so you need to write the file to a folder in the root storage which is available to anyone using the device? or you just need a safe place on the device's internal storage?
    • Biplove Lamichhane
      Biplove Lamichhane over 3 years
      In the root storage... So, that user could get the files from assets to there gallery. .create() removed.
    • David
      David over 3 years
      I'm no longer clear what the problem is, but if you want the file to be accessible by the user, you should use getExternalStorageDirectory
    • Biplove Lamichhane
      Biplove Lamichhane over 3 years
      I ll look on that
  • Biplove Lamichhane
    Biplove Lamichhane over 3 years
    Then, I get exception of FileSystemException: Cannot open file, path = '/data/user/0/com.example.pig_salang/app_flutter/images/foo.‌​jpg' (OS Error: No such file or directory, errno = 2)
  • David
    David over 3 years
    Yes, that's because you added the images folder. I meant specifically just foo.jpg, otherwise you have to create the directory as explained in the docs: api.flutter.dev/flutter/dart-io/Directory-class.html
  • David
    David over 3 years
    Sorry, my mistake, forgot to actually create the file. Then you can just use the recursive property, instead of creating the directory in a separate step. I've edited my answer.
  • Biplove Lamichhane
    Biplove Lamichhane over 3 years
    Okay... I ll look at it.
  • Yadu
    Yadu over 3 years
    why are you giving it a external directory? do rootBundle.load('assets/somefolder/somefile.png') as you are accessing a assets bundled with your app you have to look for it in assets root
  • Biplove Lamichhane
    Biplove Lamichhane over 3 years
    Please review post, as I made changes.
  • w461
    w461 over 2 years
    Is there a drawback using image.copy or why do you chose using a byte by byte copy instead?
  • damiro
    damiro over 2 years
    at that time, this is the best solution I could find. The situation is that I need to copy an Image from assets to App directory without displaying it. To answer your question, I don't think there will be draw backs if you can make if work by the use of image.copy.