【问题标题】:How to make a copy of a file in android?如何在android中制作文件的副本?
【发布时间】:2012-03-06 18:27:53
【问题描述】:

在我的应用中,我想用不同的名称(我从用户那里获得)保存某个文件的副本

我真的需要打开文件的内容并将其写入另一个文件吗?

最好的方法是什么?

【问题讨论】:

标签: java android


【解决方案1】:

要复制文件并将其保存到目标路径,您可以使用以下方法。

public static void copy(File src, File dst) throws IOException {
    InputStream in = new FileInputStream(src);
    try {
        OutputStream out = new FileOutputStream(dst);
        try {
            // Transfer bytes from in to out
            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
        } finally {
            out.close();
        }
    } finally {
        in.close();
    }
}

在 API 19+ 上,您可以使用 Java 自动资源管理:

public static void copy(File src, File dst) throws IOException {
    try (InputStream in = new FileInputStream(src)) {
        try (OutputStream out = new FileOutputStream(dst)) {
            // Transfer bytes from in to out
            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
        }
    }
}

【讨论】:

  • 谢谢。敲了敲头后,我发现问题是缺少写入外部存储的权限。现在它工作正常。
  • @mohitum007 如果文件无法复制,则会引发异常。调用方法时使用 try catch 块。
  • 如果抛出异常,流在被垃圾回收之前不会关闭,that's not good。考虑在finally 中关闭它们。
  • @Pang。你说的对。更糟糕的是,必须调用 in/out.close() 否则底层操作系统会出现资源泄漏,因为 GC 永远不会关闭打开的文件描述符。 GC 无法关闭 JVM 外部的操作系统资源,例如文件描述符或套接字。这些必须始终以编程方式在 finally 子句中关闭或使用 try-with-resource 新语法:docs.oracle.com/javase/tutorial/essential/exceptions/…
  • 请在 finally 中关闭两个 Streams,如果有异常,您的流内存将不会被收集。
【解决方案2】:

或者,您可以使用FileChannel 复制文件。在复制大文件时,它可能比字节复制方法快。 You can't use it if your file is bigger than 2GB though.

public void copy(File src, File dst) throws IOException {
    FileInputStream inStream = new FileInputStream(src);
    FileOutputStream outStream = new FileOutputStream(dst);
    FileChannel inChannel = inStream.getChannel();
    FileChannel outChannel = outStream.getChannel();
    inChannel.transferTo(0, inChannel.size(), outChannel);
    inStream.close();
    outStream.close();
}

【讨论】:

  • transferTo 可能会引发异常,在这种情况下,您将打开流。就像 Pang 和 Nima 在接受的答案中评论一样。
  • 另外,transferTo 应该在循环内部调用,因为它不能保证它会转移请求的总量。
  • 我尝试了您的解决方案,但它对我来说失败了,除了java.io.FileNotFoundException: /sdcard/AppProj/IMG_20150626_214946.jpg: open failed: ENOENT (No such file or directory)FileOutputStream outStream = new FileOutputStream(dst); 步骤。根据我意识到的文本,该文件不存在,所以我检查它并在需要时调用dst.mkdir();,但它仍然没有帮助。我还尝试检查dst.canWrite();,它返回false。这可能是问题的根源吗?是的,我有<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  • @ViktorBrešan 在 API 19 之后,您可以通过在 try try ( FileInputStream inStream = new FileInputStream(src); FileOutputStream outStream = new FileOutputStream(dst) ) {987654330@ 的开头定义输入和输出流来使用 Java 自动资源管理。
  • 有没有办法让这个解决方案将它的进度发布到onProgressUpdate,这样我就可以在 ProgressBar 中显示它?在接受的解决方案中,我可以在 while 循环中计算进度,但在这里看不到如何进行。
【解决方案3】:

它的 Kotlin 扩展

fun File.copyTo(file: File) {
    inputStream().use { input ->
        file.outputStream().use { output ->
            input.copyTo(output)
        }
    }
}

【讨论】:

  • 这是最简洁灵活的答案。更简单的答案无法解释通过 contentResolver.openInputStream(uri) 打开的 URI。
  • 嗨,我想克隆并重命名它的文件,你能帮忙吗?提前致谢
  • @famfamfam 为参数创建文件时只需传递不同的名称
  • 我找到方法复制但没有看到名称变量 sir: public fun InputStream.copyTo(out: OutputStream, bufferSize: Int = DEFAULT_BUFFER_SIZE): Long
【解决方案4】:

这在 Android O (API 26) 上很简单,如您所见:

  @RequiresApi(api = Build.VERSION_CODES.O)
  public static void copy(File origin, File dest) throws IOException {
    Files.copy(origin.toPath(), dest.toPath());
  }

【讨论】:

    【解决方案5】:

    这些对我很有效

    public static void copyFileOrDirectory(String srcDir, String dstDir) {
    
        try {
            File src = new File(srcDir);
            File dst = new File(dstDir, src.getName());
    
            if (src.isDirectory()) {
    
                String files[] = src.list();
                int filesLength = files.length;
                for (int i = 0; i < filesLength; i++) {
                    String src1 = (new File(src, files[i]).getPath());
                    String dst1 = dst.getPath();
                    copyFileOrDirectory(src1, dst1);
    
                }
            } else {
                copyFile(src, dst);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void copyFile(File sourceFile, File destFile) throws IOException {
        if (!destFile.getParentFile().exists())
            destFile.getParentFile().mkdirs();
    
        if (!destFile.exists()) {
            destFile.createNewFile();
        }
    
        FileChannel source = null;
        FileChannel destination = null;
    
        try {
            source = new FileInputStream(sourceFile).getChannel();
            destination = new FileOutputStream(destFile).getChannel();
            destination.transferFrom(source, 0, source.size());
        } finally {
            if (source != null) {
                source.close();
            }
            if (destination != null) {
                destination.close();
            }
        }
    }
    

    【讨论】:

      【解决方案6】:

      现在使用 Kotlin 变得更加简单:

       File("originalFileDir", "originalFile.name")
                  .copyTo(File("newFileDir", "newFile.name"), true)
      

      trueorfalse 用于覆盖目标文件

      https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/java.io.-file/copy-to.html

      【讨论】:

      • 如果您的文件来自 Gallery 意图 Uri,那就没那么简单了。
      • 阅读该答案下方的 cmets:“此答案是有害的,不值得获得投票。如果 Uri 是 content:// 或任何其他非文件 Uri,它将失败。” (我确实投了赞成票 - 我只是想澄清这不是灵丹妙药)
      【解决方案7】:

      答案可能为时已晚,但最方便的方法是使用

      FileUtils

      static void copyFile(File srcFile, File destFile)

      例如这就是我所做的

      `

      private String copy(String original, int copyNumber){
          String copy_path = path + "_copy" + copyNumber;
              try {
                  FileUtils.copyFile(new File(path), new File(copy_path));
                  return copy_path;
              } catch (IOException e) {
                  e.printStackTrace();
              }
              return null;
          }
      

      `

      【讨论】:

      • FileUtils 在 Android 中不存在。
      • 但是有一个由 Apache 制作的库可以做到这一点以及更多:commons.apache.org/proper/commons-io/javadocs/api-2.5/org/…
      • @TheBerga 你能详细说明一下吗?我找到了这些复制方法,但不能使用它们。这些方法的cmets声称有一些优化,所以我很想使用。
      【解决方案8】:

      在 kotlin 中,只需:

      val fileSrc : File = File("srcPath")
      val fileDest : File = File("destPath")
      
      fileSrc.copyTo(fileDest)
      

      【讨论】:

        【解决方案9】:

        如果在复制时发生错误,这是一个实际关闭输入/输出流的解决方案。此解决方案利用 apache Commons IO IOUtils 方法来复制和处理流的关闭。

            public void copyFile(File src, File dst)  {
                InputStream in = null;
                OutputStream out = null;
                try {
                    in = new FileInputStream(src);
                    out = new FileOutputStream(dst);
                    IOUtils.copy(in, out);
                } catch (IOException ioe) {
                    Log.e(LOGTAG, "IOException occurred.", ioe);
                } finally {
                    IOUtils.closeQuietly(out);
                    IOUtils.closeQuietly(in);
                }
            }
        

        【讨论】:

        • 看起来很简单
        • 你应该使用 copyStream 而不是 copy
        【解决方案10】:

        在 Kotlin 中:一条捷径

        // fromPath : Path the file you want to copy 
        // toPath :   The path where you want to save the file
        // fileName : name of the file that you want to copy
        // newFileName: New name for the copied file (you can put the fileName too instead of put a new name)    
        
        val toPathF = File(toPath)
        if (!toPathF.exists()) {
           path.mkdir()
        }
        
        File(fromPath, fileName).copyTo(File(toPath, fileName), replace)
        
        

        这适用于任何文件,例如图像和视频

        【讨论】:

          【解决方案11】:

          现在在 kotlin 中你可以使用

          file1.copyTo(file2)
          

          其中 file1 是原始文件的对象,file2 是要复制到的新文件的对象

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-10-14
            • 2012-08-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多