Cómo copiar archivos de la carpeta 'assets' a sdcard?

Tengo algunos archivos en la carpeta de assets . Necesito copiar todos ellos a una carpeta say / sdcard / folder. Quiero hacer esto desde un hilo. ¿Cómo lo hago?

    Si alguien más está teniendo el mismo problema, así es como lo hice

     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); } if (files != null) 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); } catch(IOException e) { Log.e("tag", "Failed to copy asset file: " + filename, e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { // NOOP } } if (out != null) { try { out.close(); } catch (IOException e) { // NOOP } } } } } 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); } } 

    Referencia: Mover el archivo utilizando Java

    Sobre la base de su solución, hice algo propio para permitir subcarpetas. Alguien podría encontrar esto útil:

     copyFileOrDir("myrootdir"); 

     private void copyFileOrDir(String path) { AssetManager assetManager = this.getAssets(); String assets[] = null; try { assets = assetManager.list(path); if (assets.length == 0) { copyFile(path); } else { String fullPath = "/data/data/" + this.getPackageName() + "/" + path; File dir = new File(fullPath); if (!dir.exists()) dir.mkdir(); for (int i = 0; i < assets.length; ++i) { copyFileOrDir(path + "/" + assets[i]); } } } catch (IOException ex) { Log.e("tag", "I/O Exception", ex); } } private void copyFile(String filename) { AssetManager assetManager = this.getAssets(); InputStream in = null; OutputStream out = null; try { in = assetManager.open(filename); String newFileName = "/data/data/" + this.getPackageName() + "/" + filename; out = new FileOutputStream(newFileName); byte[] buffer = new byte[1024]; int read; while ((read = in.read(buffer)) != -1) { out.write(buffer, 0, read); } in.close(); in = null; out.flush(); out.close(); out = null; } catch (Exception e) { Log.e("tag", e.getMessage()); } } 

    La solución anterior no funcionó debido a algunos errores:

    • La creación de directorios no funcionó
    • Los activos devueltos por Android contienen también tres carpetas: imágenes, sonidos y webkit
    • Añadida la extensión de .mp3 al archivo en la carpeta assets en tu proyecto y durante la copia el archivo de destino será sin la extensión .mp3

    Aquí está el código (dejé las declaraciones de registro pero puedes dejarlas ahora):

     final static String TARGET_BASE_PATH = "/sdcard/appname/voices/"; private void copyFilesToSdCard() { copyFileOrDir(""); // copy all files in assets folder in my project } private void copyFileOrDir(String path) { AssetManager assetManager = this.getAssets(); String assets[] = null; try { Log.i("tag", "copyFileOrDir() "+path); assets = assetManager.list(path); if (assets.length == 0) { copyFile(path); } else { String fullPath = TARGET_BASE_PATH + path; Log.i("tag", "path="+fullPath); File dir = new File(fullPath); if (!dir.exists() && !path.startsWith("images") && !path.startsWith("sounds") && !path.startsWith("webkit")) if (!dir.mkdirs()) Log.i("tag", "could not create dir "+fullPath); for (int i = 0; i < assets.length; ++i) { String p; if (path.equals("")) p = ""; else p = path + "/"; if (!path.startsWith("images") && !path.startsWith("sounds") && !path.startsWith("webkit")) copyFileOrDir( p + assets[i]); } } } catch (IOException ex) { Log.e("tag", "I/O Exception", ex); } } private void copyFile(String filename) { AssetManager assetManager = this.getAssets(); InputStream in = null; OutputStream out = null; String newFileName = null; try { Log.i("tag", "copyFile() "+filename); in = assetManager.open(filename); if (filename.endsWith(".jpg")) // extension was added to avoid compression on APK file newFileName = TARGET_BASE_PATH + filename.substring(0, filename.length()-4); else newFileName = TARGET_BASE_PATH + filename; out = new FileOutputStream(newFileName); byte[] buffer = new byte[1024]; int read; while ((read = in.read(buffer)) != -1) { out.write(buffer, 0, read); } in.close(); in = null; out.flush(); out.close(); out = null; } catch (Exception e) { Log.e("tag", "Exception in copyFile() of "+newFileName); Log.e("tag", "Exception in copyFile() "+e.toString()); } } 

    EDIT: Corregido un extraviado ";" Que estaba lanzando un sistemático "no pudo crear dir" error.

    Sé que esto se ha contestado pero tengo una manera levemente más elegante de copiar del directorio del activo a un archivo en el sdcard. No requiere bucle "for", sino que utiliza File Streams y Channels para realizar el trabajo.

    (Nota) Si utiliza cualquier tipo de archivo comprimido, APK, PDF, … puede cambiar el nombre de la extensión de archivo antes de insertar en el activo y luego cambiar el nombre una vez que lo copie a SDcard)

     AssetManager am = context.getAssets(); AssetFileDescriptor afd = null; try { afd = am.openFd( "MyFile.dat"); // Create new file to copy into. File file = new File(Environment.getExternalStorageDirectory() + java.io.File.separator + "NewFile.dat"); file.createNewFile(); copyFdToFile(afd.getFileDescriptor(), file); } catch (IOException e) { e.printStackTrace(); } 

    Una manera de copiar un archivo sin tener que recorrerlo.

     public static void copyFdToFile(FileDescriptor src, File dst) throws IOException { FileChannel inChannel = new FileInputStream(src).getChannel(); FileChannel outChannel = new FileOutputStream(dst).getChannel(); try { inChannel.transferTo(0, inChannel.size(), outChannel); } finally { if (inChannel != null) inChannel.close(); if (outChannel != null) outChannel.close(); } } 

    Buen ejemplo. Respondió a mi pregunta de cómo acceder a los archivos de la carpeta de activos.

    Sólo el cambio que yo sugiero está en el bucle for. El siguiente formato funcionaría también y se prefiere:

      for(String filename : files) { InputStream in = null; OutputStream out = null; try { in = assetManager.open(filename); out = new FileOutputStream("/sdcard/" + filename); ... } 

    Probar esto es mucho más simple, esto ayudará u:

     // Open your local db as the input stream InputStream myInput = _context.getAssets().open(YOUR FILE NAME); // Path to the just created empty db String outFileName =SDCARD PATH + YOUR FILE NAME; // Open the empty db as the output stream OutputStream myOutput = new FileOutputStream(outFileName); // transfer bytes from the inputfile to the outputfile byte[] buffer = new byte[1024]; int length; while ((length = myInput.read(buffer)) > 0) { myOutput.write(buffer, 0, length); } // Close the streams myOutput.flush(); myOutput.close(); myInput.close(); 

    Aquí está una versión limpia para dispositivos Android actuales, diseño de método funcional para que pueda copiarlo a una clase AssetsHelper, por ejemplo;)

     /** * * Info: prior to Android 2.3, any compressed asset file with an * uncompressed size of over 1 MB cannot be read from the APK. So this * should only be used if the device has android 2.3 or later running! * * @param c * @param targetFolder * eg {@link Environment#getExternalStorageDirectory()} * @throws Exception */ @TargetApi(Build.VERSION_CODES.GINGERBREAD) public static boolean copyAssets(AssetManager assetManager, File targetFolder) throws Exception { Log.i(LOG_TAG, "Copying files from assets to folder " + targetFolder); return copyAssets(assetManager, "", targetFolder); } /** * The files will be copied at the location targetFolder+path so if you * enter path="abc" and targetfolder="sdcard" the files will be located in * "sdcard/abc" * * @param assetManager * @param path * @param targetFolder * @return * @throws Exception */ public static boolean copyAssets(AssetManager assetManager, String path, File targetFolder) throws Exception { Log.i(LOG_TAG, "Copying " + path + " to " + targetFolder); String sources[] = assetManager.list(path); if (sources.length == 0) { // its not a folder, so its a file: copyAssetFileToFolder(assetManager, path, targetFolder); } else { // its a folder: if (path.startsWith("images") || path.startsWith("sounds") || path.startsWith("webkit")) { Log.i(LOG_TAG, " > Skipping " + path); return false; } File targetDir = new File(targetFolder, path); targetDir.mkdirs(); for (String source : sources) { String fullSourcePath = path.equals("") ? source : (path + File.separator + source); copyAssets(assetManager, fullSourcePath, targetFolder); } } return true; } private static void copyAssetFileToFolder(AssetManager assetManager, String fullAssetPath, File targetBasePath) throws IOException { InputStream in = assetManager.open(fullAssetPath); OutputStream out = new FileOutputStream(new File(targetBasePath, fullAssetPath)); byte[] buffer = new byte[16 * 1024]; int read; while ((read = in.read(buffer)) != -1) { out.write(buffer, 0, read); } in.close(); out.flush(); out.close(); } 

    Copie todos los archivos y directorios de los activos a su carpeta!

    Para copiar mejor use apache commons io

     public void doCopyAssets() throws IOException { File externalFilesDir = context.getExternalFilesDir(null); doCopy("", externalFilesDir.getPath()); } 

    // ESTE ES EL MÉTODO PRINCIPAL PARA COPIAR

     private void doCopy(String dirName, String outPath) throws IOException { String[] srcFiles = assets.list(dirName);//for directory for (String srcFileName : srcFiles) { String outFileName = outPath + File.separator + srcFileName; String inFileName = dirName + File.separator + srcFileName; if (dirName.equals("")) {// for first time inFileName = srcFileName; } try { InputStream inputStream = assets.open(inFileName); copyAndClose(inputStream, new FileOutputStream(outFileName)); } catch (IOException e) {//if directory fails exception new File(outFileName).mkdir(); doCopy(inFileName, outFileName); } } } 

    // ESTO DESDE COMMON IO

     public static void closeQuietly(OutputStream output) { try { if(output != null) { output.close(); } } catch(IOException ioe) { //skip } } public static void closeQuietly(InputStream input) { try { if(input != null) { input.close(); } } catch(IOException ioe) { //skip } } public static void copyAndClose(InputStream input, OutputStream output) throws IOException { copy(input, output); closeQuietly(input); closeQuietly(output); } public static void copy(InputStream input, OutputStream output) throws IOException { byte[] buffer = new byte[1024]; int n = 0; while(-1 != (n = input.read(buffer))) { output.write(buffer, 0, n); } } 

    Modificado esta respuesta por @DannyA

     private void copyAssets(String path, String outPath) { AssetManager assetManager = this.getAssets(); String assets[]; try { assets = assetManager.list(path); if (assets.length == 0) { copyFile(path, outPath); } else { String fullPath = outPath + "/" + path; File dir = new File(fullPath); if (!dir.exists()) if (!dir.mkdir()) Log.e(TAG, "No create external directory: " + dir ); for (String asset : assets) { copyAssets(path + "/" + asset, outPath); } } } catch (IOException ex) { Log.e(TAG, "I/O Exception", ex); } } private void copyFile(String filename, String outPath) { AssetManager assetManager = this.getAssets(); InputStream in; OutputStream out; try { in = assetManager.open(filename); String newFileName = outPath + "/" + filename; out = new FileOutputStream(newFileName); byte[] buffer = new byte[1024]; int read; while ((read = in.read(buffer)) != -1) { out.write(buffer, 0, read); } in.close(); out.flush(); out.close(); } catch (Exception e) { Log.e(TAG, e.getMessage()); } } 

    Preparativos

    En src/main/assets agregar carpeta con fold nombre

    Uso

     File outDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString()); copyAssets("fold",outDir.toString()); 

    En el directorio externo encontrar todos los archivos y directorios que se encuentran dentro de los activos veces

    Basado en la respuesta de Yoram Cohen, aquí hay una versión que soporta directorio de destino no estático.

    Invoque con copyFileOrDir(getDataDir(), "") para escribir en la carpeta de almacenamiento interna de la aplicación / data / data / pkg_name /

    • Soporta subcarpetas.
    • Soporta directorio de destino personalizado y no estático
    • Evita copiar "imágenes", etc.

       private void copyFileOrDir(String TARGET_BASE_PATH, String path) { AssetManager assetManager = this.getAssets(); String assets[] = null; try { Log.i("tag", "copyFileOrDir() "+path); assets = assetManager.list(path); if (assets.length == 0) { copyFile(TARGET_BASE_PATH, path); } else { String fullPath = TARGET_BASE_PATH + "/" + path; Log.i("tag", "path="+fullPath); File dir = new File(fullPath); if (!dir.exists() && !path.startsWith("images") && !path.startsWith("sounds") && !path.startsWith("webkit")) if (!dir.mkdirs()) Log.i("tag", "could not create dir "+fullPath); for (int i = 0; i < assets.length; ++i) { String p; if (path.equals("")) p = ""; else p = path + "/"; if (!path.startsWith("images") && !path.startsWith("sounds") && !path.startsWith("webkit")) copyFileOrDir(TARGET_BASE_PATH, p + assets[i]); } } } catch (IOException ex) { Log.e("tag", "I/O Exception", ex); } } private void copyFile(String TARGET_BASE_PATH, String filename) { AssetManager assetManager = this.getAssets(); InputStream in = null; OutputStream out = null; String newFileName = null; try { Log.i("tag", "copyFile() "+filename); in = assetManager.open(filename); if (filename.endsWith(".jpg")) // extension was added to avoid compression on APK file newFileName = TARGET_BASE_PATH + "/" + filename.substring(0, filename.length()-4); else newFileName = TARGET_BASE_PATH + "/" + filename; out = new FileOutputStream(newFileName); byte[] buffer = new byte[1024]; int read; while ((read = in.read(buffer)) != -1) { out.write(buffer, 0, read); } in.close(); in = null; out.flush(); out.close(); out = null; } catch (Exception e) { Log.e("tag", "Exception in copyFile() of "+newFileName); Log.e("tag", "Exception in copyFile() "+e.toString()); } } 

    Use AssetManager , que permite leer los archivos en los activos. A continuación, utilice Java IO normal para escribir los archivos en sdcard.

    Google es tu amigo, busca un ejemplo.

     import android.app.Activity; import android.content.Intent; import android.content.res.AssetManager; import android.net.Uri; import android.os.Environment; import android.os.Bundle; import android.util.Log; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); copyReadAssets(); } private void copyReadAssets() { AssetManager assetManager = getAssets(); InputStream in = null; OutputStream out = null; String strDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)+ File.separator + "Pdfs"; File fileDir = new File(strDir); fileDir.mkdirs(); // crear la ruta si no existe File file = new File(fileDir, "example2.pdf"); try { in = assetManager.open("example.pdf"); //leer el archivo de assets out = new BufferedOutputStream(new FileOutputStream(file)); //crear el archivo copyFile(in, out); in.close(); in = null; out.flush(); out.close(); out = null; } catch (Exception e) { Log.e("tag", e.getMessage()); } Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse("file://" + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + File.separator + "Pdfs" + "/example2.pdf"), "application/pdf"); startActivity(intent); } 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); } } } 

    Cambiar partes de código como estos:

     out = new BufferedOutputStream(new FileOutputStream(file)); 

    El ejemplo anterior es para Pdfs, en caso de ejemplo .txt

     FileOutputStream fos = new FileOutputStream(file); 

    Hola chicos hice algo como esto. Para N-ésima carpeta de copia de profundidad y archivos para copiar. Que le permite copiar toda la estructura de directorios para copiar desde Android AssetManager 🙂

      private void manageAssetFolderToSDcard() { try { String arg_assetDir = getApplicationContext().getPackageName(); String arg_destinationDir = FRConstants.ANDROID_DATA + arg_assetDir; File FolderInCache = new File(arg_destinationDir); if (!FolderInCache.exists()) { copyDirorfileFromAssetManager(arg_assetDir, arg_destinationDir); } } catch (IOException e1) { e1.printStackTrace(); } } 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"); } } } 

    Al final, crea un Asynctask:

      private class ManageAssetFolders extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... arg0) { manageAssetFolderToSDcard(); return null; } } 

    Llámelo De su actividad:

      new ManageAssetFolders().execute(); 

    Una ligera modificación de la respuesta anterior para copiar una carpeta recursivamente y para acomodar el destino personalizado.

     public void copyFileOrDir(String path, String destinationDir) { AssetManager assetManager = this.getAssets(); String assets[] = null; try { assets = assetManager.list(path); if (assets.length == 0) { copyFile(path,destinationDir); } else { String fullPath = destinationDir + "/" + path; File dir = new File(fullPath); if (!dir.exists()) dir.mkdir(); for (int i = 0; i < assets.length; ++i) { copyFileOrDir(path + "/" + assets[i], destinationDir + path + "/" + assets[i]); } } } catch (IOException ex) { Log.e("tag", "I/O Exception", ex); } } private void copyFile(String filename, String destinationDir) { AssetManager assetManager = this.getAssets(); String newFileName = destinationDir + "/" + filename; InputStream in = null; OutputStream out = null; try { in = assetManager.open(filename); out = new FileOutputStream(newFileName); byte[] buffer = new byte[1024]; int read; while ((read = in.read(buffer)) != -1) { out.write(buffer, 0, read); } in.close(); in = null; out.flush(); out.close(); out = null; } catch (Exception e) { Log.e("tag", e.getMessage()); } new File(newFileName).setExecutable(true, false); } 

    Hay esencialmente dos maneras de hacer esto.

    En primer lugar, puede utilizar AssetManager.open y, según lo descrito por Rohith Nandakumar e iterar sobre el inputtream.

    En segundo lugar, puede utilizar AssetManager.openFd , que le permite utilizar un FileChannel (que tiene el [transferTo] ( https://developer.android.com/reference/java/nio/channels/FileChannel.html#transferTo(long , Largo, java.nio.channels.WritableByteChannel)) y [transferFrom] ( https://developer.android.com/reference/java/nio/channels/FileChannel.html#transferFrom(java.nio.channels.ReadableByteChannel , largo, Largo))), por lo que no tiene que hacer un bucle sobre el flujo de entrada usted mismo.

    Describiré el método openFd aquí.

    Compresión

    Primero debe asegurarse de que el archivo se almacena sin comprimir. El sistema de empaque puede optar por comprimir cualquier archivo con una extensión que no esté marcada como noCompress , y los archivos comprimidos no se pueden asignar a la memoria, por lo que tendrá que confiar en AssetManager.open en ese caso.

    Puede agregar una extensión '.mp3' a su archivo para evitar que se comprima, pero la solución adecuada es modificar su archivo app / build.gradle y agregar las siguientes líneas (para desactivar la compresión de archivos PDF)

     aaptOptions { noCompress 'pdf' } 

    Embalaje de archivo

    Tenga en cuenta que el empaquetador todavía puede empaquetar varios archivos en uno, por lo que no puede leer todo el archivo que le ofrece AssetManager . Necesita pedir al AssetFileDescriptor qué partes necesita.

    Encontrar la parte correcta del archivo empaquetado

    Una vez que haya asegurado que su archivo se almacena descomprimido, puede utilizar el método AssetManager.openFd para obtener un AssetFileDescriptor , que puede utilizarse para obtener un FileInputStream (a diferencia de AssetManager.open , que devuelve un InputStream ) que contiene un FileChannel . También contiene el offset inicial (getStartOffset) y size (getLength) , que necesita para obtener la parte correcta del archivo.

    Implementación

    A continuación se ofrece un ejemplo de implementación:

     private void copyFileFromAssets(String in_filename, File out_file){ Log.d("copyFileFromAssets", "Copying file '"+in_filename+"' to '"+out_file.toString()+"'"); AssetManager assetManager = getApplicationContext().getAssets(); FileChannel in_chan = null, out_chan = null; try { AssetFileDescriptor in_afd = assetManager.openFd(in_filename); FileInputStream in_stream = in_afd.createInputStream(); in_chan = in_stream.getChannel(); Log.d("copyFileFromAssets", "Asset space in file: start = "+in_afd.getStartOffset()+", length = "+in_afd.getLength()); FileOutputStream out_stream = new FileOutputStream(out_file); out_chan = out_stream.getChannel(); in_chan.transferTo(in_afd.getStartOffset(), in_afd.getLength(), out_chan); } catch (IOException ioe){ Log.w("copyFileFromAssets", "Failed to copy file '"+in_filename+"' to external storage:"+ioe.toString()); } finally { try { if (in_chan != null) { in_chan.close(); } if (out_chan != null) { out_chan.close(); } } catch (IOException ioe){} } } 

    Esta respuesta se basa en la respuesta de JPM .

    Utilizando algunos de los conceptos en las respuestas a esta pregunta, escribí una clase llamada AssetCopier para hacer copiar /assets/ simple. Está disponible en github y se puede acceder con jitpack.io :

     new AssetCopier(MainActivity.this) .withFileScanning() .copy("tocopy", destDir); 

    Consulte https://github.com/flipagram/android-assetcopier para obtener más detalles.

    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.