Как скопировать файлы из папки «assets» в SDCard?

У меня есть несколько файлов в папке с assets . Мне нужно скопировать все их в папку say / sdcard / folder. Я хочу сделать это из потока. Как мне это сделать?

Solutions Collecting From Web of "Как скопировать файлы из папки «assets» в SDCard?"

Если у кого-то еще такая же проблема, вот как я это сделал

 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); } } 

Ссылка: перемещение файла с использованием Java

Основываясь на вашем решении, я сделал что-то свое, чтобы разрешить вложенные папки. Кто-то может найти это полезным:

 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()); } } 

Решение выше не работает из-за некоторых ошибок:

  • Создание каталога не сработало
  • Активы, возвращенные Android, содержат также три папки: изображения, звуки и webkit
  • Добавлен способ работы с большими файлами: добавьте расширение .mp3 в файл в папке с ресурсами в вашем проекте, и во время копирования целевой файл будет без расширения .mp3

Вот код (я оставил логические операторы, но теперь их можно отбросить):

 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: Исправлено неуместное ";" Что бросало систематическую ошибку «не удалось создать dir».

Я знаю, что на это был дан ответ, но у меня есть несколько более элегантный способ скопировать из каталога ресурсов в файл на SD-карте. Он не требует цикла «для», но вместо этого использует файловые потоки и каналы для выполнения этой работы.

(Примечание) Если вы используете любой тип сжатого файла, APK, PDF, … вы можете переименовать расширение файла, прежде чем вставлять его в актив, а затем переименовать после его копирования на SD-карту)

 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(); } 

Способ копирования файла без необходимости его прокрутки.

 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(); } } 

Хороший пример. Ответил мой вопрос о том, как получить доступ к файлам в папке с ресурсами.

Только изменение, которое я предлагаю, находится в цикле for. Следующий формат будет работать и является предпочтительным:

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

Попробуйте, это намного проще, это поможет 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(); 

Вот очищенная версия для текущих Android-устройств, функциональный дизайн метода, чтобы вы могли скопировать его в класс AssetsHelper, например;)

 /** * * 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(); } 

Скопируйте все файлы и каталоги из активов в свою папку!

Для копирования лучше использовать apache commons io

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

// ЭТО ГЛАВНЫЙ МЕТОД ДЛЯ КОПИРОВАНИЯ

 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); } } } 

// ЭТО ОТ commons 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); } } 

Изменен этот ответ SO @ by @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()); } } 

Препараты

В src/main/assets добавить папку с именем fold

Применение

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

Во внешнем каталоге найдите все файлы и каталоги, находящиеся в фоновых активах

Основываясь на ответе Йорума Коэна, вот версия, которая поддерживает нестационарный целевой каталог.

Invoque with copyFileOrDir(getDataDir(), "") для записи во внутреннюю папку хранения данных / data / data / pkg_name /

  • Поддерживает подпапки.
  • Поддерживает настраиваемый и нестатический целевой каталог
  • Избегает копирования копий «изображений» и т. Д.

     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()); } } 

Используйте AssetManager , он позволяет читать файлы в активах. Затем используйте обычный Java IO для записи файлов на SDCard.

Google – ваш друг, ищите пример.

 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); } } } 

Измените части кода следующим образом:

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

Предыдущий пример для Pdfs, в случае, например, .txt

 FileOutputStream fos = new FileOutputStream(file); 

Привет, ребята, я сделал что-то подобное. Для N-й копии и копий копии копий. Который позволяет скопировать всю структуру каталогов для копирования из 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"); } } } 

В конце создайте Asynctask:

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

Назовите его Из вашей деятельности:

  new ManageAssetFolders().execute(); 

Небольшая модификация вышеприведенного ответа, чтобы скопировать папку рекурсивно и разместить заказное место назначения.

 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); } 

Есть два способа сделать это.

Во-первых, вы можете использовать AssetManager.open и, как описано Rohith Nandakumar, и итерации по входному потоку .

Во-вторых, вы можете использовать AssetManager.openFd , который позволяет использовать FileChannel (который имеет [transferTo] ( https://developer.android.com/reference/java/nio/channels/FileChannel.html#transferTo(long , Long, java.nio.channels.WritableByteChannel)) и [transferFrom] ( https://developer.android.com/reference/java/nio/channels/FileChannel.html#transferFrom(java.nio.channels.ReadableByteChannel , long, Long))), поэтому вам не нужно самостоятельно перебирать входной поток.

Здесь я опишу метод openFd.

компрессия

Сначала вам нужно убедиться, что файл сохранен несжатым. Система упаковки может сжать любой файл с расширением, которое не помечено как noCompress , а сжатые файлы не могут быть отображены в память, поэтому в этом случае вам придется полагаться на AssetManager.open .

Вы можете добавить расширение «.mp3» в свой файл, чтобы остановить его от сжатия, но правильным решением является изменение вашего файла app / build.gradle и добавление следующих строк (чтобы отключить сжатие PDF-файлов)

 aaptOptions { noCompress 'pdf' } 

Упаковка файлов

Обратите внимание, что упаковщик все еще может упаковать несколько файлов в один, поэтому вы не можете просто прочитать весь файл, предоставленный AssetManager . Вам нужно спросить у AssetFileDescriptor, какие части вам нужны.

Поиск правильной части упакованного файла

После того, как вы сохранили файл без сжатия, вы можете использовать метод AssetManager.openFd для получения AssetFileDescriptor , который можно использовать для получения FileInputStream (в отличие от AssetManager.open , который возвращает InputStream ), который содержит FileChannel . Он также содержит начальное смещение (getStartOffset) и размер (getLength) , которые вам нужны для получения правильной части файла.

Реализация

Пример реализации приведен ниже:

 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){} } } 

Этот ответ основан на ответе JPM .

Используя некоторые понятия в ответах на этот вопрос, я написал класс под названием AssetCopier чтобы сделать копирование /assets/ просто. Он доступен в github и доступен с помощью jitpack.io :

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

Подробнее см. https://github.com/flipagram/android-assetcopier .