复制的 DocumentFile 具有与原始文件不同的大小和哈希值

Copied DocumentFile has different siize and hash to original

我正在尝试在 Android 应用程序中复制/复制 DocumentFile,但在检查创建的副本时,它似乎与原始副本不完全相同(这导致了问题,因为我需要在下次调用副本时对两个文件进行MD5检查,以避免覆盖相同的文件。

过程如下:

  1. 用户从ACTION_OPEN_DOCUMENT_TREE
  2. 中选择了一个文件
  3. 获取源文件类型
  4. 目标位置的新文档文件已初始化
  5. 第一个文件的内容被复制到第二个文件中

初始阶段使用以下代码完成:

// Get the source file's type
String sourceFileType = MimeTypeMap.getSingleton().getExtensionFromMimeType(contextRef.getContentResolver().getType(file.getUri()));

// Create the new (empty) file
DocumentFile newFile = targetLocation.createFile(sourceFileType, file.getName());

// Copy the file
CopyBufferedFile(new BufferedInputStream(contextRef.getContentResolver().openInputStream(file.getUri())), new BufferedOutputStream(contextRef.getContentResolver().openOutputStream(newFile.getUri())));

主要复制过程使用以下代码段完成:

    void CopyBufferedFile(BufferedInputStream bufferedInputStream, BufferedOutputStream bufferedOutputStream)
    {
        // Duplicate the contents of the temporary local File to the DocumentFile
        try
        {
            byte[] buf = new byte[1024];
            bufferedInputStream.read(buf);

            do
            {
                bufferedOutputStream.write(buf);
            }
            while(bufferedInputStream.read(buf) != -1);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if (bufferedInputStream != null) bufferedInputStream.close();
                if (bufferedOutputStream != null) bufferedOutputStream.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

我面临的问题是,虽然文件复制成功并且可以使用(它是一张猫的图片,并且在目的地仍然是一张猫的图片),但它略有不同。

  1. 文件大小已从 2261840 更改为 2262016 (+176)
  2. MD5 哈希已完全改变

我的复制代码是否有问题导致文件发生轻微变化?

提前致谢。

您的复制代码不正确。它假设(错误地)每次调用 read 将 return buffer.length 字节或 return -1.

应该做的是每次捕获变量中读取的字节数,然后准确地写入该字节数。您关闭流的代码很冗长并且(理论上1)也有错误。

这是一个解决了这两个问题和其他一些问题的重写。

void copyBufferedFile(BufferedInputStream bufferedInputStream,
                      BufferedOutputStream bufferedOutputStream)
         throws IOException 
{
    try (BufferedInputStream in = bufferedInputStream;
         BufferedOutputStream out = bufferedOutputStream) 
    {
        byte[] buf = new byte[1024];
        int nosRead;
        while ((nosRead = in.read(buf)) != -1)  // read this carefully ...
        {
            out.write(buf, 0, nosRead);
        }
    }
}

如您所见,我已经摆脱了伪造的 "catch and squash exception" 处理程序,并使用 Java 7+ try with resources 修复了资源泄漏.

还有几个问题:

  1. copy函数最好以文件名字符串(或FilePath对象)为参数,负责打开流

  2. 鉴于您正在进行块读写,使用缓冲流的价值不大。 (事实上​​ ,它可能会使 I/O 变慢。)最好使用纯流并使缓冲区大小与 Buffered* 类 使用的默认缓冲区大小相同.... 或更大。

  3. 如果您真的很在意性能,请尝试使用 transferFrom,如下所述:


1 - 理论上,如果 bufferedInputStream.close() 抛出异常,将跳过 bufferedOutputStream.close() 调用。实际上,关闭输入流不太可能引发异常。但无论哪种方式,try with resource 方法都可以正确且简洁地处理此问题。