Android - 将资产复制到内部存储

46

您好!

我刚开始开发Android应用程序。在我的应用程序中,我需要将我的资产文件夹中的项目复制到内部存储中。

我已经在SO上搜索了很多,包括这个可以将其复制到外部存储的问题。 如何从'assets'文件夹复制文件到sdcard?

这就是我想要实现的: 我在内部存储中已经有一个目录X>Y>Z。我需要将一个文件复制到Y和另一个文件复制到Z。

有人能帮我提供一小段代码吗?我真的不知道该怎么做。

对我的糟糕的英语感到抱歉。

谢谢。


2
你尝试使用你在帖子中分享的链接了吗?你遇到了什么错误? - Mothy
尝试一下我建议的方法,它对我有效 :) - DropAndTrap
8个回答

30

使用

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

        File outFile = new File(out, Filename);
在您提供的参考链接答案进行编辑后。
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);
     }
   }

4
String out = Environment.getExternalStorageDirectory().getAbsolutePath() + "/X/Y/Z/";File outFile = new File(dirout, Filename); 将"out"更改为"dirout",它与下一个字符串"out"的冲突。 - temple
5
不,从Environment.getExternalStorageDirectory()函数的调用中可以明显看出,这将数据复制到外部存储。 - Chris Stratton
1
我认为关于物理存储和逻辑存储之间的区别可能存在一些混淆。内置存储器(即非SD卡)可能具有某些逻辑“外部”存储器,因此不太清楚提问者正在询问什么。 - Chris B
1
很棒的答案。你应该记得使用MediaScannerConnection来扫描新文件。 - Juliano Rodrigo Lamb
1
当使用FileOutputStream时,flush()是无用的,因为OutputStreamflush()的实现为空。 - Zhou Hongbo
显示剩余6条评论

18
我做了类似于这样的事情。这可以让你复制所有的目录结构,从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");
        }
    }
}

5
他说这样做可以复制整个目录结构,而被接受的答案则不行。这是最佳答案 :) - ale.m
1
如何获取和传递arg_assetDir参数? - Chitrang

13

这是我使用自动关闭流在内部应用程序存储中进行复制的Kotlin解决方案:

val copiedFile = File(context.filesDir, "copied_file.txt")
context.assets.open("original_file.txt").use { input ->
    copiedFile.outputStream().use { output ->
        input.copyTo(output, 1024)
    }
}

10

尝试以下代码

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

7
以下为翻译:如何将 assets 中的文件复制到 SD 卡?在 Android 中,assets 目录存放着一些应用程序需要使用到的文件,例如图片、音频和文本文件等。有时候我们需要将这些文件复制到设备的 SD 卡中,以便于用户可以在其他应用程序中使用或者进行备份。以下是实现该功能的代码示例: - GrIsHu
1
请问您能否解释一下如何指定要复制到哪个目录?谢谢。 - Noob Android
1
在这一行代码中,您需要根据需要更改路径:File outFile = new File(getExternalFilesDir(null), filename); - Sanket Kachhela
1
文件 outFile = new File(getExternalFilesDir(null), "/MYFolder/Bhlabhla"); - Auto-Droid ツ
这样的代码:File outFile = new File(Environment.getExternalStorageDirectory()+"/yourfolder", filename); - Sanket Kachhela
显示剩余4条评论

7

这是我用Kotlin编写的小程序,用于将数据从assets复制到内部存储

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

当使用FileOutputStream时,flush()是无用的,因为在OutputStream中的flush()的实现为空。 同时你也可以使用Stream.use{}来省略对close的调用。 - Zhou Hongbo

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

             }
         }

要添加文件,调用addFilesToSystem("this_file_is_in_the_public_system", "this_file_is_in_the_assets_folder", context/如果您在Activity中没有该方法,则需要此上下文
希望能有所帮助。

0
如果您需要将资产中的任何文件复制到内部存储器,并且只需要执行一次:
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;
}

0

你可以使用Envrionment#getDataDirectory方法来实现。它会返回内部存储器中数据目录的路径。通常情况下,这是所有应用程序相关数据存储的位置。

或者,如果你想要存储在根目录中,你可以使用Environment#getRootDirectory方法来实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接