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

Roh*_*mar 242 android assets copy

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

Roh*_*mar 341

如果其他人遇到同样的问题,我就这样做了

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

参考:使用Java移动文件

  • 要在SD卡中写入文件,你必须在清单上给予权限,例如<uses-permission android:name ="android.permission.WRITE_EXTERNAL_STORAGE"/> (28认同)
  • 我也不会依赖sdcard位于/ sdcard,而是使用Environment.getExternalStorageDirectory()检索路径 (22认同)
  • 对我来说,这个代码只有在我添加它时才有效:`in = assetManager.open("images-wall /"+ filename);`where"images-wall"是我资产中的文件夹 (7认同)
  • @rciovati得到了这个运行时错误`无法复制资产文件:myfile.txt java.io.FileNotFoundException:myfile.txt at android.content.res.AssetManager.openAsset(Native Method) (3认同)
  • 我应该使用:16*1024(16kb)我倾向于选择16K或32K作为内存使用和性能之间的良好平衡. (2认同)

Dan*_*nyA 60

根据您的解决方案,我做了一些自己的事情来允许子文件夹.有人可能会觉得这很有帮助:

...

copyFileOrDir("myrootdir");
Run Code Online (Sandbox Code Playgroud)

...

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

}
Run Code Online (Sandbox Code Playgroud)

  • 好的解决方案 唯一需要修复的是在copyFileOrDir()的开头修剪前导分隔符:path = path.startsWith("/")?path.substring(1):path; (3认同)
  • 用this.getFilesDir()替换"/ data/data /"+ this.getPackageName().getAbsolutePath() (2认同)

小智 49

由于某些错误,上述解决方案无效:

  • 目录创建不起作用
  • Android返回的资产还包含三个文件夹:图像,声音和webkit
  • 添加了处理大文件的方法:将扩展名.mp3添加到项目的assets文件夹中的文件中,并且在复制期间,目标文件将没有.mp3扩展名

这是代码(我离开了Log语句,但你现在可以删除它们):

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

}
Run Code Online (Sandbox Code Playgroud)

编辑:纠正错位的";" 这是一个系统的"无法创建目录"的错误.

  • 这必须成为解决方案! (4认同)

JPM*_*JPM 31

我知道这已经得到了解答,但我有一种更优雅的方式从资产目录复制到SD卡上的文件.它不需要"for"循环,而是使用File Streams和Channels来完成工作.

(注意)如果使用任何类型的压缩文件,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();
}
Run Code Online (Sandbox Code Playgroud)

一种复制文件而无需循环的方法.

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这对我来说不会超过文件描述符,`这个文件不能作为文件描述符打开; 它可能是压缩的 - 它是一个pdf文件.知道如何解决这个问题吗? (3认同)

小智 10

这在 Kotlin 中将是简洁的方式。

    fun AssetManager.copyRecursively(assetPath: String, targetFile: File) {
        val list = list(assetPath)
        if (list.isEmpty()) { // assetPath is file
            open(assetPath).use { input ->
                FileOutputStream(targetFile.absolutePath).use { output ->
                    input.copyTo(output)
                    output.flush()
                }
            }

        } else { // assetPath is folder
            targetFile.delete()
            targetFile.mkdir()

            list.forEach {
                copyRecursively("$assetPath/$it", File(targetFile, it))
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)


GOL*_*DEE 5

试试这个,它更简单,这将帮助你:

// 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();
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

182273 次

最近记录:

6 年,3 月 前