【问题标题】:How to copy files from 'assets' folder to sdcard?如何将文件从“资产”文件夹复制到 SD 卡?
【发布时间】:2011-05-25 18:02:21
【问题描述】:

assets 文件夹中有一些文件。我需要将它们全部复制到一个文件夹中,例如 /sdcard/folder。我想从一个线程中做到这一点。我该怎么做?

【问题讨论】:

标签: android copy assets


【解决方案1】:

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

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

参考:Move file using Java

【讨论】:

  • 要在 sdcard 中写入文件,您必须授予清单上的权限,例如
  • 我也不会依赖位于 /sdcard 的 sdcard,而是使用 Environment.getExternalStorageDirectory() 检索路径
  • 我应该使用:16* 1024 (16kb) 我倾向于选择 16K 或 32K 作为内存使用和性能之间的良好平衡。
  • @rciovati 收到此运行时错误Failed to copy asset file: myfile.txt java.io.FileNotFoundException: myfile.txt at android.content.res.AssetManager.openAsset(Native Method)
  • 对我而言,此代码仅在我添加此代码时才有效:in = assetManager.open("images-wall/"+filename); 其中“images-wall”是我在资产中的文件夹
【解决方案2】:

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

...

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

}

【讨论】:

  • assetManager.list(path) 在设备上可能很慢,要预先创建资产路径列表,可以从assets dir: find . -name "*" -type f -exec ls -l {} \; | awk '{print substr($9,3)}' &gt;&gt; assets.list 使用这个 sn-p
  • 不错的解决方案!唯一需要的修复是在 copyFileOrDir() 开头修剪前导分隔符: path= path.startsWith("/") ? path.substring(1) : 路径;
  • 这个stackoverflow在某些设备上,例如:S5
  • 用 this.getFilesDir().getAbsolutePath() 替换 "/data/data/" + this.getPackageName()
  • ...并关闭finally块中的流))
【解决方案3】:

由于一些错误,上述解决方案不起作用:

  • 目录创建失败
  • Android 返回的资产还包含三个文件夹:images、sounds 和 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());
    }

}

编辑:更正了一个放错位置的“;”这引发了系统性的“无法创建目录”错误。

【讨论】:

  • 这必须成为解决方案!
  • 注意:Log.i("tag", "could not create dir "+fullPath);总是发生为 ;在 if 上放错了位置。
  • 太棒了!非常感谢!但是为什么要检查 jpg 文件呢?
【解决方案4】:

我知道这个问题已经得到解答,但我有一种更优雅的方式可以从资产目录复制到 sdcard 上的文件。它不需要“for”循环,而是使用文件流和通道来完成工作。

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

【讨论】:

  • 比其他解决方案更喜欢这个,有点整洁。对我的轻微修改,包括创建丢失的文件文件夹。干杯!
  • 这对我来说无法通过文件描述符This file can not be opened as a file descriptor; it is probably compressed——它是一个pdf文件。知道如何解决吗?
  • 这假定 inChannel.size() 返回文件大小的大小。它使no such guarantee。我得到 2.5 MiB 的 2 个文件,每个文件 450 KiB。
  • 我刚刚发现 AssetFileDescriptor.getLength() 会返回正确的文件大小。
  • 除上述之外,资产可能不在文件描述符中的位置 0 处开始。 AssetFileDescriptor.getStartOffset() 将返回起始偏移量。
【解决方案5】:

这将是 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))
            }
        }
    }

【讨论】:

  • list(assetPath)?.let { ... },实际上。它是可空的。
【解决方案6】:

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

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

【讨论】:

    【解决方案7】:

    这是针对当前 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
     *            e.g. {@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();
    }
    

    【讨论】:

      【解决方案8】:

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

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

      【讨论】:

        【解决方案9】:

        使用这个问题的答案中的一些概念,我编写了一个名为AssetCopier 的类,以使复制/assets/ 变得简单。它在github 上可用,可以通过jitpack.io 访问:

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

        更多详情请见https://github.com/flipagram/android-assetcopier。

        【讨论】:

          【解决方案10】:

          将所有文件和目录从资产复制到您的文件夹!

          为了更好地复制使用 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);
                  }
          
              }
          }
          
          public static void closeQuietly(AutoCloseable autoCloseable) {
              try {
                  if(autoCloseable != null) {
                      autoCloseable.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);
              }
          }
          

          【讨论】:

            【解决方案11】:

            基于 Rohith Nandakumar 的解决方案,我自己做了一些事情来从资产的子文件夹(即“assets/MyFolder”)复制文件。另外,在尝试再次复制之前,我正在检查文件是否已存在于 sdcard 中。

            private void copyAssets() {
                AssetManager assetManager = getAssets();
                String[] files = null;
                try {
                    files = assetManager.list("MyFolder");
                } 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("MyFolder/"+filename);
                      File outFile = new File(getExternalFilesDir(null), filename);
                      if (!(outFile.exists())) {// File does not exist...
                            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);
                }
            }
            

            【讨论】:

              【解决方案12】:

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

              【讨论】:

                【解决方案13】:

                基本上有两种方法可以做到这一点。

                首先,您可以使用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](@ 987654326@, long, long)) 方法),因此您不必自己循环输入流。

                我将在这里描述openFd方法。

                压缩

                首先,您需要确保文件未压缩存储。打包系统可能会选择压缩任何扩展名没有标记为 noCompress 的文件,并且压缩后的文件无法进行内存映射,因此您将不得不依赖 AssetManager.open 在那种情况下。

                您可以在文件中添加“.mp3”扩展名以阻止其被压缩,但正确的解决方案是修改您的 app/build.gradle 文件并添加以下行(到禁用 PDF 文件压缩)

                aaptOptions {
                    noCompress 'pdf'
                }
                

                文件打包

                请注意,打包程序仍然可以将多个文件打包成一个,因此您不能只读取 AssetManager 提供给您的整个文件。您需要询问 AssetFileDescriptor 您需要哪些部分。

                找到打包文件的正确部分

                一旦您确保文件未压缩存储,您可以使用 AssetManager.openFd 方法获取 AssetFileDescriptor,该方法可用于获取 FileInputStream(与返回 InputStream 的 AssetManager.open 不同)包含 FileChannel。它还包含starting offset (getStartOffset) 和size (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's answer。

                【讨论】:

                  【解决方案14】:

                  您可以使用 Kotlin 分几步完成,这里我只是将几个文件而不是所有文件从 asstes 复制到我的应用程序文件目录。

                  private fun copyRelatedAssets() {
                      val assets = arrayOf("myhome.html", "support.css", "myscript.js", "style.css")
                      assets.forEach {
                          val inputStream = requireContext().assets.open(it)
                          val nameSplit = it.split(".")
                          val name = nameSplit[0]
                          val extension = nameSplit[1]
                          val path = inputStream.getFilePath(requireContext().filesDir, name, extension)
                          Log.v(TAG, path)
                      }
                  }
                  

                  这里是扩展功能,

                  fun InputStream.getFilePath(dir: File, name: String, extension: String): String {
                      val file = File(dir, "$name.$extension")
                      val outputStream = FileOutputStream(file)
                      this.copyTo(outputStream, 4096)
                      return file.absolutePath
                  }
                  

                  LOGCAT

                  /data/user/0/com.***.***/files/myhome.html
                  /data/user/0/com.***.***/files/support.css
                  /data/user/0/com.***.***/files/myscript.js
                  /data/user/0/com.***.***/files/style.css
                  

                  【讨论】:

                    【解决方案15】:
                    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);
                    

                    【讨论】:

                      【解决方案16】:

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

                      【讨论】:

                        【解决方案17】:

                        对上述答案稍作修改,以递归方式复制文件夹并适应自定义目标。

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

                        【讨论】:

                          【解决方案18】:

                          对于那些正在更新到 Kotlin 的人:

                          按照this 的步骤避免FileUriExposedExceptions, 假设用户已授予WRITE_EXTERNAL_STORAGE 权限,并且您的文件位于assets/pdfs/mypdf.pdf。

                          private fun openFile() {
                              var inputStream: InputStream? = null
                              var outputStream: OutputStream? = null
                              try {
                                  val file = File("${activity.getExternalFilesDir(null)}/$PDF_FILE_NAME")
                                  if (!file.exists()) {
                                      inputStream = activity.assets.open("$PDF_ASSETS_PATH/$PDF_FILE_NAME")
                                      outputStream = FileOutputStream(file)
                                      copyFile(inputStream, outputStream)
                                  }
                          
                                  val uri = FileProvider.getUriForFile(
                                      activity,
                                      "${BuildConfig.APPLICATION_ID}.provider.GenericFileProvider",
                                      file
                                  )
                                  val intent = Intent(Intent.ACTION_VIEW).apply {
                                      setDataAndType(uri, "application/pdf")
                                      addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                                      addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
                                  }
                                  activity.startActivity(intent)
                              } catch (ex: IOException) {
                                  ex.printStackTrace()
                              } catch (ex: ActivityNotFoundException) {
                                  ex.printStackTrace()
                              } finally {
                                  inputStream?.close()
                                  outputStream?.flush()
                                  outputStream?.close()
                              }
                          }
                          
                          @Throws(IOException::class)
                          private fun copyFile(input: InputStream, output: OutputStream) {
                              val buffer = ByteArray(1024)
                              var read: Int = input.read(buffer)
                              while (read != -1) {
                                  output.write(buffer, 0, read)
                                  read = input.read(buffer)
                              }
                          }
                          
                          companion object {
                              private const val PDF_ASSETS_PATH = "pdfs"
                              private const val PDF_FILE_NAME = "mypdf.pdf"
                          }
                          

                          【讨论】:

                            【解决方案19】:

                            这是我的个性化文本提取器类,希望对你有用。

                            package lorenzo.morelli.platedetector;
                            
                            import android.content.Context;
                            import android.content.res.AssetManager;
                            import android.graphics.Bitmap;
                            
                            import com.googlecode.tesseract.android.TessBaseAPI;
                            
                            import java.io.File;
                            import java.io.FileOutputStream;
                            import java.io.IOException;
                            import java.io.InputStream;
                            import java.io.OutputStream;
                            
                            public class TextExtractor {
                            
                                private final Context context;
                                private final String dirName;
                                private final String language;
                            
                                public TextExtractor(final Context context, final String dirName, final String language) {
                                    this.context = context;
                                    this.dirName = dirName;
                                    this.language = language;
                                }
                            
                                public String extractText(final Bitmap bitmap) {
                                    final TessBaseAPI tessBaseApi = new TessBaseAPI();
                                    final String datapath = this.context.getFilesDir()+ "/tesseract/";
                                    checkFile(new File(datapath + this.dirName + "/"), datapath, this.dirName, this.language);
                            
                                    tessBaseApi.init(datapath, this.language);
                                    tessBaseApi.setImage(bitmap);
                                    final String extractedText = tessBaseApi.getUTF8Text();
                                    tessBaseApi.end();
                                    return extractedText;
                                }
                            
                                private void checkFile(final File dir, final String datapath, final String dirName, final String language) {
                                    //directory does not exist, but we can successfully create it
                                    if (!dir.exists()&& dir.mkdirs()) {
                                        copyFiles(datapath, dirName, language);
                                    } //The directory exists, but there is no data file in it
                                    if(dir.exists()) {
                                        final String datafilepath = datapath + "/" + dirName + "/" + language + ".traineddata";
                                        final File datafile = new File(datafilepath);
                                        if (!datafile.exists()) {
                                            copyFiles(datapath, dirName, language);
                                        }
                                    }
                                }
                            
                                private void copyFiles(final String datapath, final String dirName, final String language) {
                                    try {
                                        //location we want the file to be at
                                        final String filepath = datapath + "/" + dirName + "/" + language + ".traineddata";
                            
                                        //get access to AssetManager
                                        final AssetManager assetManager = this.context.getAssets();
                            
                                        //open byte streams for reading/writing
                                        final InputStream instream = assetManager.open(dirName + "/" + language + ".traineddata");
                                        final OutputStream outstream = new FileOutputStream(filepath);
                            
                                        //copy the file to the location specified by filepath
                                        byte[] buffer = new byte[1024];
                                        int read;
                                        while ((read = instream.read(buffer)) != -1) {
                                            outstream.write(buffer, 0, read);
                                        }
                                        outstream.flush();
                                        outstream.close();
                                        instream.close();
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                            
                            

                            要使用它,您需要经过训练的数据文件。你可以从这个link下载trainddata文件。

                            下载所需的训练数据文件后,您需要在您的 android 项目中创建一个名为 assets 的 Android 资源目录。在新创建的资产文件夹中,您需要创建一个名为“tessdata”的常规目录,您可以在其中放置您的训练数据文件。 最后,您必须在 MainActivity 中初始化“TextExtractor”类。

                            final TextExtractor textExtractor = new TextExtractor(this, "tessdata", "eng");
                            

                            第一个参数是上下文,第二个是刚刚创建的目录的名称,最后一个是刚刚下载的训练数据的语言。

                            要提取文本,您必须调用“extractText”方法:

                            final String text = textExtractor.extractText(imageWithText);
                            

                            请注意,extractText 需要一个位图图像才能工作!! 您可以使用以下行从您的可绘制文件创建位图图像:

                            final BitMap image = BitmapFactory.decodeResource(getResources(), R.drawable.test_image);
                            

                            如果您需要更多支持,我建议您遵循这个有用的指南:https://github.com/SamVanRoy/Android_OCR_App

                            【讨论】:

                              【解决方案20】:

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

                              Google 是您的朋友,请搜索示例。

                              【讨论】:

                                【解决方案21】:

                                这是迄今为止我在互联网上找到的最佳解决方案。 我使用了以下链接 https://gist.github.com/mhasby/026f02b33fcc4207b302a60645f6e217,
                                但它有一个错误,我修复了它,然后它就像一个魅力。 这是我的代码。你可以轻松使用它,因为它是一个独立的 java 类。

                                public class CopyAssets {
                                public static void copyAssets(Context context) {
                                    AssetManager assetManager = context.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);
                                
                                            out = new FileOutputStream(Environment.getExternalStorageDirectory()+"/www/resources/" + filename);
                                            copyFile(in, out);
                                        } catch(IOException e) {
                                            Log.e("tag", "Failed to copy asset file: " + filename, e);
                                        }
                                        finally {
                                            if (in != null) {
                                                try {
                                                    in.close();
                                                    in = null;
                                                } catch (IOException e) {
                                
                                                }
                                            }
                                            if (out != null) {
                                                try {
                                                    out.flush();
                                                    out.close();
                                                    out = null;
                                                } catch (IOException e) {
                                
                                                }
                                            }
                                        }
                                    }
                                }
                                
                                public static 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 类中创建 CopyAssets 的实例。现在这部分很重要,就我在互联网上的测试和研究而言,You cannot use AssetManager if the class has no activity。它与 java 类的上下文有关。
                                现在,c.copyAssets(getApplicationContext()) 是访问该方法的一种简单方法,其中c 是CopyAssets 类的实例。 根据我的要求,我允许程序将我在asset 文件夹中的所有资源文件复制到我的内部目录的/www/resources/。
                                您可以根据使用情况轻松找到需要对目录进行更改的部分。 如果您需要任何帮助,请随时联系我。

                                【讨论】:

                                  【解决方案22】:

                                  您也可以使用 Guava 的ByteStream 将文件从 assets 文件夹复制到 SD 卡。这是我最终得到的解决方案,它将文件从资产文件夹递归复制到 SD 卡:

                                  /**
                                   * Copies all assets in an assets directory to the SD file system.
                                   */
                                  public class CopyAssetsToSDHelper {
                                  
                                      public static void copyAssets(String assetDir, String targetDir, Context context) 
                                          throws IOException {
                                          AssetManager assets = context.getAssets();
                                          String[] list = assets.list(assetDir);
                                          for (String f : Objects.requireNonNull(list)) {
                                              if (f.indexOf(".") > 1) { // check, if this is a file
                                                  File outFile = new File(context.getExternalFilesDir(null), 
                                                      String.format("%s/%s", targetDir, f));
                                                  File parentFile = outFile.getParentFile();
                                                  if (!Objects.requireNonNull(parentFile).exists()) {
                                                      if (!parentFile.mkdirs()) {
                                                          throw new IOException(String.format("Could not create directory %s.", 
                                                              parentFile));
                                                      }
                                                  }
                                                  try (InputStream fin = assets.open(String.format("%s/%s", assetDir, f));
                                                       OutputStream fout = new FileOutputStream(outFile)) {
                                                      ByteStreams.copy(fin, fout);
                                                  }
                                              } else { // This is a directory
                                                  copyAssets(String.format("%s/%s", assetDir, f), String.format("%s/%s", targetDir, f), 
                                                      context);
                                              }
                                          }
                                      }
                                  
                                  }
                                  

                                  【讨论】:

                                    猜你喜欢
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2014-02-10
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2011-08-08
                                    相关资源
                                    最近更新 更多