如何将文件从'资产'文件夹复制到SD卡?

assets文件夹中有几个文件。 我需要将它们全部复制到一个文件夹说/ SD卡/文件夹。 我想从一个线程内做到这一点。 我该怎么做?

如果其他人有同样的问题,这是我怎么做的

 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移动文件

基于你的解决scheme,我做了一些我自己的,允许子文件夹。 有人可能会觉得这有帮助:

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

上面的解决scheme由于一些错误而不起作用:

  • 目录创build不起作用
  • Android返回的资产还包含三个文件夹:图像,声音和webkit
  • 增加处理大文件的方法:将扩展名.mp3添加到项目中assets文件夹中的文件中,并在复制期间将目标文件的扩展名为.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()); } } 

编辑:更正了错位“;” 那就是抛出一个系统的“不能创造dir”的错误。

我知道这已被回答,但我有一个稍微更优雅的方式,从资产目录复制到SD卡上的文件。 它不需要“for”循环,而是使用文件stream和频道来完成这项工作。

(注)如果使用任何types的压缩文件,APK,PDF,…您可能需要在插入资源之前重命名文件扩展名,然后在将其复制到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(); } 

一种复制文件的方法,无需循环。

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

很好的例子。 回答了我如何访问资产文件夹中的文件的问题。

只有改变我会build议是在for循环。 以下格式也可以工作,是首选:

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

试试这简单得多,这将有助于你:

 // 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设备的清理版本,function方法devise,以便您可以将其复制到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); } } 

通过@DannyA修改了这个SO回答

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

在外部目录中查找折叠资产中的所有文件和目录

根据Yoram Cohen的回答,这里是一个支持非静态目标目录的版本。

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

使用AssetManager ,它允许读取资产中的文件。 然后使用常规Java IO将文件写入SD卡。

Google是你的朋友,search一个例子。

嗨,伙计们,我做了这样的事情。 对于第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"); } } } 

最后创build一个Asynctask:

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

打电话给你从你的活动:

  new ManageAssetFolders().execute(); 

上面的答案略有修改recursion复制一个文件夹,并容纳自定义的目的地。

 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所述,并遍历inputstream。

其次,你可以使用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,长))方法),所以你不必循环inputstream自己。

我将在这里描述openFd方法。

压缩

首先,您需要确保文件未压缩存储。 打包系统可以select使用未标记为noCompress的扩展名来压缩任何文件,并且压缩文件不能被映射到内存,所以在这种情况下您将不得不依赖于AssetManager.open

你可以在你的文件中添加一个'.mp3'扩展名来阻止它被压缩,但是正确的解决scheme是修改你的app / build.gradle文件并添加下面的行(禁止压缩PDF文件)

 aaptOptions { noCompress 'pdf' } 

文件打包

请注意,打包程序仍然可以打包多个文件,因此您不能只读取AssetManager提供的整个文件。 您需要询问AssetFileDescriptor您需要的零件。

find打包文件的正确部分

一旦确保文件未压缩存储,您可以使用AssetManager.openFd方法获取AssetFileDescriptor ,该文件可用于获取包含FileChannelFileInputStream (与AssetManager.open不同,后者返回InputStream )。 它还包含起始偏移量(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