44

Good day!

I have just started developing for android. In my app, I need to copy the items in my assets folder to the internal storage.

I have searched a lot on SO including this which copies it to the external storage. How to copy files from 'assets' folder to sdcard?

This is what I want to achieve: I have a directory already present in the internal storage as X>Y>Z. I need a file to be copied to Y and another to Z.

Can anyone help me out with a code snippet? I really don't have any idea how to go on about this.

Sorry for my bad English.

Thanks a lot.

Community
  • 1
  • 1
Noob Android
  • 443
  • 1
  • 4
  • 6

8 Answers8

30

Use

 String out= Environment.getExternalStorageDirectory().getAbsolutePath() + "/X/Y/Z/" ; 

        File outFile = new File(out, Filename);

After Editing in your ref. Link Answer.

private void copyAssets() {
    AssetManager assetManager = getAssets();
    String[] files = null;
try {
    files = assetManager.list("");
} catch (IOException e) {
    Log.e("tag", "Failed to get asset file list.", e);
  }
 for(String filename : files) {
    InputStream in = null;
    OutputStream out = null;
    try {
      in = assetManager.open(filename);

      String outDir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/X/Y/Z/" ; 

      File outFile = new File(outDir, filename);

      out = new FileOutputStream(outFile);
      copyFile(in, out);
      in.close();
      in = null;
      out.flush();
      out.close();
        out = null;
      } catch(IOException e) {
          Log.e("tag", "Failed to copy asset file: " + filename, e);
         }       
       }
     }
     private void copyFile(InputStream in, OutputStream out) throws IOException {
        byte[] buffer = new byte[1024];
      int read;
     while((read = in.read(buffer)) != -1){
       out.write(buffer, 0, read);
     }
   }
Pheepster
  • 6,045
  • 6
  • 41
  • 75
AmmY
  • 1,821
  • 1
  • 20
  • 31
  • How should I use this code? Please elaborate a little. I'm really new to android. Thank you. – Noob Android Oct 07 '13 at 07:28
  • 4
    String out= Environment.getExternalStorageDirectory().getAbsolutePath() + "/X/Y/Z/" ; File outFile = new File(out, Filename); change the "out" to "dirout". it is conflicting with the next String out – temple Jun 17 '14 at 00:00
  • 5
    No, as should be obvious from the Environment.getExternalStorageDirectory() call this copies the data to the **EXTERNAL** storage. – Chris Stratton Jul 29 '14 at 14:40
  • No, It copies the data to mobile's inbuilt storage where songs,images are stored. – AmmY Jul 30 '14 at 05:41
  • I believe that use of `Environment.getExternalStorageDirectory()` will result in a security exception in new Android versions – Someone Somewhere Dec 16 '15 at 18:59
  • Use System.getenv("EXTERNAL_STORAGE"); to get the correct the path or you may try it by yourself in a shell by executing "echo $EXTERNAL_STORAGE". – ShihabSoft Mar 02 '16 at 19:34
  • 1
    I think that there may be some confusion about the difference between physical and logical storage. The built-in storage (i.e. not the SD card) may have some logical "external" storage in it, so it's not really clear what the asker is asking. – Chris B Apr 18 '16 at 04:07
  • 1
    Great answer. You should remember to use the MediaScannerConnection to scan the new files. – Juliano Rodrigo Lamb Sep 16 '19 at 15:02
  • It throws java.lang.IOException. –  Jun 22 '20 at 16:37
  • @HyperCreeck Check the link for new documentation. https://developer.android.com/training/data-storage/app-specific – AmmY Jun 25 '20 at 11:40
  • 1
    When using FileOutputStream, `flush()` is useless, because the implemention of `flush()` in `OutputStream` is empty. – Zhou Hongbo Jun 05 '22 at 14:55
18

I did something like this. This allows you to copy all the directory structure to copy from Android AssetManager.

public String copyDirorfileFromAssetManager(String arg_assetDir, String arg_destinationDir) throws IOException
{
    File sd_path = Environment.getExternalStorageDirectory(); 
    String dest_dir_path = sd_path + addLeadingSlash(arg_destinationDir);
    File dest_dir = new File(dest_dir_path);

    createDir(dest_dir);

    AssetManager asset_manager = getApplicationContext().getAssets();
    String[] files = asset_manager.list(arg_assetDir);

    for (int i = 0; i < files.length; i++)
    {

        String abs_asset_file_path = addTrailingSlash(arg_assetDir) + files[i];
        String sub_files[] = asset_manager.list(abs_asset_file_path);

        if (sub_files.length == 0)
        {
            // It is a file
            String dest_file_path = addTrailingSlash(dest_dir_path) + files[i];
            copyAssetFile(abs_asset_file_path, dest_file_path);
        } else
        {
            // It is a sub directory
            copyDirorfileFromAssetManager(abs_asset_file_path, addTrailingSlash(arg_destinationDir) + files[i]);
        }
    }

    return dest_dir_path;
}


public void copyAssetFile(String assetFilePath, String destinationFilePath) throws IOException
{
    InputStream in = getApplicationContext().getAssets().open(assetFilePath);
    OutputStream out = new FileOutputStream(destinationFilePath);

    byte[] buf = new byte[1024];
    int len;
    while ((len = in.read(buf)) > 0)
        out.write(buf, 0, len);
    in.close();
    out.close();
}

public String addTrailingSlash(String path)
{
    if (path.charAt(path.length() - 1) != '/')
    {
        path += "/";
    }
    return path;
}

public String addLeadingSlash(String path)
{
    if (path.charAt(0) != '/')
    {
        path = "/" + path;
    }
    return path;
}

public void createDir(File dir) throws IOException
{
    if (dir.exists())
    {
        if (!dir.isDirectory())
        {
            throw new IOException("Can't create directory, a file is in the way");
        }
    } else
    {
        dir.mkdirs();
        if (!dir.isDirectory())
        {
            throw new IOException("Unable to create directory");
        }
    }
}
peterh
  • 11,875
  • 18
  • 85
  • 108
DropAndTrap
  • 1,538
  • 16
  • 24
12

This is my Kotlin solution with auto-closable streams to copy in internal app storage:

val copiedFile = File(context.filesDir, "copied_file.txt")
context.assets.open("original_file.txt").use { input ->
    copiedFile.outputStream().use { output ->
        input.copyTo(output, 1024)
    }
}
MatPag
  • 41,742
  • 14
  • 105
  • 114
10

try this below code

private void copyAssets() {
    AssetManager assetManager = getAssets();
    String[] files = null;
    try {
        files = assetManager.list("");
    } catch (IOException e) {
        Log.e("tag", "Failed to get asset file list.", e);
    }
    for(String filename : files) {
        InputStream in = null;
        OutputStream out = null;
        try {
          in = assetManager.open(filename);
          File outFile = new File(getExternalFilesDir(null), filename);
          out = new FileOutputStream(outFile);
          copyFile(in, out);
          in.close();
          in = null;
          out.flush();
          out.close();
          out = null;
        } catch(IOException e) {
            Log.e("tag", "Failed to copy asset file: " + filename, e);
        }       
    }
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
    byte[] buffer = new byte[1024];
    int read;
    while((read = in.read(buffer)) != -1){
      out.write(buffer, 0, read);
    }
}
Sanket Kachhela
  • 10,861
  • 8
  • 50
  • 75
6

My small solution on Kotlin, for copy data from assets to INTERNAL STORAGE

fun copy() {
    val bufferSize = 1024
    val assetManager = context.assets
    val assetFiles = assetManager.list("")

    assetFiles.forEach {
        val inputStream = assetManager.open(it)
        val outputStream = FileOutputStream(File(context.filesDir, it))

        try {
            inputStream.copyTo(outputStream, bufferSize)
        } finally {
            inputStream.close()
            outputStream.flush()
            outputStream.close()
        }
    }
}
Vova
  • 956
  • 8
  • 22
  • When using FileOutputStream, `flush()` is useless, because the implemention of `flush()` in `OutputStream` is empty. And you can also use `Stream.use{}` to omit the call of `close` – Zhou Hongbo Jun 05 '22 at 14:53
1
public void addFilesToSystem(String sysName, String intFil, Context c){
             //sysName is the name of the file we have in the android os
             //intFil is the name of the internal file



             file = new File(path, sysName + ".txt");

             if(!file.exists()){
                 path.mkdirs();

                 try {

                     AssetManager am = c.getAssets();

                     InputStream is = am.open(intFil);
                     OutputStream os = new FileOutputStream(file);
                     byte[] data = new byte[is.available()];
                     is.read(data);
                     os.write(data);
                     is.close();
                     os.close();

                     Toast t = Toast.makeText(c, "Making file: " + file.getName() + ". One time action", Toast.LENGTH_LONG);
                     t.show();

                     //Update files for the user to use
                     MediaScannerConnection.scanFile(c,
                             new String[] {file.toString()},
                             null, 
                             new MediaScannerConnection.OnScanCompletedListener() {

                         public void onScanCompleted(String path, Uri uri) {
                             // TODO Auto-generated method stub

                         }
                     });



                 }  catch (IOException e) {
                     Toast t = Toast.makeText(c, "Error: " + e.toString() + ". One time action", Toast.LENGTH_LONG);
                     t.show();
                     e.printStackTrace();
                 }

             }
         }

To add a file, call the addFilesToSystem("this_file_is_in_the_public_system", "this_file_is_in_the_assets_folder", context/this context is if you do not have the method in the Activity/

Hope it helps

0

You can use the Envrionment#getDataDirectory method for that. It'll give the path of the data directory of the internal storage memory. This is generally where all the app related data is stored.

Alternately, if you want to store in the root directory, you can use the Environment#getRootDirectory method for that.

Rahul
  • 44,383
  • 11
  • 84
  • 103
0

If you need to copy any file from assets to the internal storage and do it only once:

public void writeFileToStorage() {
        Logger.d(TAG, ">> writeFileToStorage");

        AssetManager assetManager = mContext.getAssets();
        if (new File(getFilePath()).exists()) {
            Logger.d(TAG, "File exists, do nothing");
            Logger.d(TAG, "<< writeFileToStorage");
            return;
        }

        try (InputStream input = assetManager.open(FILE_NAME);
             OutputStream output = new FileOutputStream(getFilePath())) {

            Logger.d(TAG, "File does not exist, write it");

            byte[] buffer = new byte[input.available()];
            int length;
            while ((length = input.read(buffer)) != -1) {
                output.write(buffer, 0, length);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Logger.e(TAG, "File is not found");
        } catch (IOException e) {
            e.printStackTrace();
            Logger.d(TAG, "Error while writing the file");
        }

        Logger.d(TAG, "<< writeFileToStorage");
    }

public String getFilePath() {
    String filePath = mContext.getFilesDir() + "/" + FILE_NAME;
    Logger.d(TAG, "File path: " + filePath);
    return filePath;
}
VolodymyrH
  • 1,927
  • 2
  • 18
  • 47