Файлы неправильно копируются с помощью Java

#java

#java

Вопрос:

Я написал небольшую программу, которая просто считывает содержимое файлов и записывает его в новую копию. Это отлично работает с текстовыми файлами, но с PNG и видеофайлами не удается правильно создать файл (изображение полностью черное или видео не воспроизводится). Я знаю, что есть API, которые могут копировать файлы с помощью одной строки, но я хотел бы знать, почему это не работает. Вот код:

 import java.io.*;

public class CopyFile
{
    public static void main(String[] args) throws Exception
    {
        File file = new File("test.mp4");
    File copy = new File("copy.mp4");

    InputStreamReader input = new InputStreamReader(new FileInputStream(file));
    OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(copy));

    System.out.println(input.ready());

    while(input.ready())
    {
        int i = input.read();
        //System.out.print( (char) ( (byte) i));
        out.write(i);
    }

    input.close();
    out.flush();
    out.close();
}
  

}

Комментарии:

1. Не используйте input.ready , полагайтесь на то, что input.read говорит

Ответ №1:

  1. Не используйте Reader и Writer , если вы не знаете, что ввод — это текст. Используйте InputStream и OutputStream.
  2. Также не используйте ready(), or, в интересах Sotirios. available() Ни один из них не является допустимым тестом для end of stream. Оба они касаются того, можно ли читать входные данные без блокировки, что совсем не одно и то же. См. Javadoc.
  3. Вы неправильно определяете конец потока. Если read() возвращает -1, вы все равно копируете это на вывод.
  4. Копирование одного символа или одного байта за раз выполняется чрезвычайно медленно.

Канонический способ копирования потоков в Java заключается в следующем:

 while ((count = in.read(buffer)) > 0)
{
    out.write(buffer, 0, count);
}
  

где count — это int, и buffer byte[] любой размер, больший нуля, обычно 8192.

Ответ №2:

Reader s и Writer s предназначены для чтения потоков символов (т. Е. Текста). Изображения и видео представляют собой двоичные данные, а не текст, и, вероятно, будут повреждены, если вы передадите их через потоки символов. Это связано с тем, что в зависимости от набора символов не обязательно существует обратимое сопоставление между байтами и символами. Некоторые последовательности байтов являются тарабарщиной, если интерпретируются как символы, затем тарабарщина записывается обратно в файл.

Используйте InputStream and OutputStream , которые вы открываете напрямую, вместо того, чтобы оборачивать их как Reader and Writer , и это будет работать правильно. Это потоки байтов, и они могут обрабатывать данные любого типа.

Например.,

 InputStream input = new FileInputStream(file);
OutputStream out = new FileOutputStream(copy);
  

PS Это все равно будет довольно медленно. Вы можете обернуть потоки в BufferedInputStream и BufferedOutputStream для простого способа повышения производительности, хотя API-интерфейсы однострочного копирования, вероятно, все равно будут быстрее.

Комментарии:

1. Вы определили одну проблему из как минимум четырех.

2. @EJP 2 из 3 по моим подсчетам, но да.