Скопированный DocumentFile имеет разный размер и хэш оригинала - PullRequest
0 голосов
/ 05 октября 2019

Я пытаюсь скопировать / продублировать DocumentFile в приложении Android, но после проверки созданного дубликата он не выглядит точно так же, как оригинал (что вызывает проблему, потому что мне нужно сделатьMD5 проверяет оба файла при следующем вызове копии, чтобы избежать перезаписи одних и тех же файлов).

Процесс выглядит следующим образом:

  1. Пользователь выбирает файл изACTION_OPEN_DOCUMENT_TREE
  2. Получен тип исходного файла
  3. Инициализирован новый DocumentFile в целевом местоположении
  4. Содержимое первого файла дублируется во второй файл

начальные этапы выполняются с помощью следующего кода:

// 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 полностью изменился

Что-то не так с моим кодом копирования, из-за которого файлнемного измениться?

Заранее спасибо.

1 Ответ

1 голос
/ 05 октября 2019

Ваш код копирования неверен. Предполагается (неправильно), что каждый вызов read будет либо возвращать buffer.length байтов, либо будет возвращать -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);
        }
    }
}

Как вы можете видеть, я избавился от поддельного "исключения ловли и сквоша"обработчики и исправили утечку ресурсов, используя Java 7+ , попробуйте с ресурсами .

Есть еще несколько проблем:

  1. Лучше, чтобы функция копирования принимала строки с именами файлов (или File или Path объекты) какпараметры и нести ответственность за открытие потоков.

  2. Учитывая, что вы выполняете чтение и запись блоков, использование буферизованных потоков мало что дает. (Действительно, это, возможно, может замедлить ввод / вывод.) Было бы лучше использовать простые потоки и сделать буфер того же размера, что и размер буфера по умолчанию, используемый классами Buffered* .... или больше.

  3. Если вы действительно беспокоитесь о производительности, попробуйте использовать transferFrom, как описано здесь:


1 - Теоретически, если bufferedInputStream.close() выдает исключение, вызов bufferedOutputStream.close() будет пропущен. На практике маловероятно, что закрытие входного потока вызовет исключение. Но в любом случае, попытка с ресурсом будет иметь дело с этим правильно и гораздо более кратко.

...