Поток байтов против потока символов в Java

Я работаю над классами ввода-вывода в Java. Я понимаю, что есть два важных типа потоков: поток байтов и поток символов. Но... Я попытался прочитать и записать текстовый файл с потоком байтов, и это сработало. Вот код:

    File klasor = new File("C:\\Java");
    if(!klasor.exists()) klasor.mkdirs();

    File kaynakDosya = new File("C:\\Java\\kaynak.txt");
    if(!kaynakDosya.exists()) kaynakDosya.createNewFile();

    File hedefDosya = new File("C:\\Java\\hedef.txt");
    if(!hedefDosya.exists()) hedefDosya.createNewFile();

    FileInputStream kaynak = new FileInputStream(kaynakDosya);
    FileOutputStream hedef = new FileOutputStream(hedefDosya);

    int c;
    while((c = kaynak.read()) != -1) {
        hedef.write(c);
    }

    if(kaynak != null) {
        kaynak.close();
    }

    if(hedef != null) {
        hedef.close();
    }

И затем я сделал то же самое с потоком символов:

    File klasor = new File("C:\\Java");
    if(!klasor.exists()) klasor.mkdirs();

    File kaynakDosya = new File("C:\\Java\\kaynak.txt");
    if(!kaynakDosya.exists()) kaynakDosya.createNewFile();

    File hedefDosya = new File("C:\\Java\\hedef.txt");
    if(!hedefDosya.exists()) hedefDosya.createNewFile();

    FileReader kaynak = new FileReader(kaynakDosya);
    FileWriter hedef = new FileWriter(hedefDosya);

    int c;
    while((c = kaynak.read()) != -1) {
        hedef.write(c);
    }

    if(kaynak != null) {
        kaynak.close();
    }

    if(hedef != null) {
        hedef.close();
    }

Эти двое дали один и тот же результат. Итак, я хочу знать, почему я не должен использовать здесь поток байтов, а поток символов? (Я прочитал некоторые статьи, а также связанные вопросы здесь, в stackoverflow, и они так говорят) Я знаю, что поток символов будет читать его посимвольно, но какое преимущество это дает мне? Или какие проблемы могут возникнуть, если я читаю символы, используя поток байтов? Надеюсь, мой вопрос понятен. Буду признателен за реальные примеры.


person Community    schedule 22.10.2017    source источник


Ответы (2)


java.io.FileInputStream в javadoc указано:

FileInputStream предназначен для чтения потоков необработанных байтов, таких как данные изображения. Для чтения потоков символов рассмотрите возможность использования FileReader.

java.io.FileOutputStream javadoc утверждает что-то похожее:

FileOutputStream предназначен для записи потоков необработанных байтов, таких как данные изображения. Для записи потоков символов рассмотрите возможность использования FileWriter.

Одно из основных различий между FileInputStream/FileOutputStream и FileReader/FileWriter заключается в том, что первый предоставляет методы для манипулирования байтами, а второй предоставляет методы для манипулирования символами.

В вашем примере, когда вы копируете содержимое файла в другой файл, манипулирование char или byte не имеет большого значения.
В вашем случае FileInputStream или BufferedInputStream кажутся даже более подходящими.

Но если вы используете поток для чтения/записи символов из/в экземпляры String, использование FileReader/FileWriter действительно облегчает задачу и делает ее более понятной.
Кроме того, вы также можете обернуть FileReader/FileWriter в BufferedReader/BufferedWriter и извлечь выгоду из эффективного чтения/записи символов. , массивы и строки.

 BufferedWriter writer = new BufferedWriter(new FileWriter("myfile"));
 writer.append(oneString);
 writer.append(oneStringBuffer);
 writer.newLine();

 BufferedReader reader = new BufferedReader(new FileReader("myfile"));
 String currentLine = reader.readLine();
person davidxxx    schedule 22.10.2017

Запись символов в поток вывода, ориентированный на байты (или чтение символов из потока ввода, ориентированный на байты) приведет к тем же результатам, что и использование потоков, ориентированных на символы, только если все символы в потоке могут быть представлены одиночными байтами по умолчанию. кодировка вашей платформы (обычно UTF-8, но может быть и другая). Чтобы проверить это, попробуйте файл, содержащий что-то, для представления которого требуется более одного байта (например, греческие, кириллические или арабские символы). С потоком, ориентированным на байты, они не будут работать. В символьно-ориентированном потоке символы будут сохраняться до тех пор, пока оба потока используют кодировку, поддерживающую эти символы (например, UTF-8), и входной файл был сохранен в кодировке, используемой для входного потока.

Обратите внимание, что ваш байт-ориентированный код на самом деле не проверяет это, поскольку он просто копирует файл байт за байтом. Все будет выглядеть так, как будто это работает, но если вы попытаетесь прочитать фактические символы (скажем, сравнить их с реальным текстом в коде), это не удастся. Чтобы проверить это, создайте файл (скажем, в кодировке UTF-8), содержащий кириллический текст "Привет!" Затем в коде попробуйте прочитать этот текст, используя байт-ориентированный входной поток, в String и проверьте, действительно ли он содержит то, что вы ожидаете, используя

System.out.println("Success: " + "Привет!".equals(input));
person Ted Hopp    schedule 22.10.2017
comment
Я запутался: разве все символы не представлены двумя байтами? Что вы имеете в виду, если все символы в файле могут быть представлены одним байтом? Пробовал с кириллицей Привет! и это тоже сработало! Плюс я оставил кодировку исходного файла UTF-8 и изменил кодировку целевого файла на ANSI, все равно заработало. - person ; 22.10.2017
comment
@AdemTepe - в UTF-8 кодовые точки до 0x7F представлены одним байтом. (См. эту тему, например.) Ваш байт-ориентированный код отлично работает для простого копирования файла байт за байтом, но это не касается того, что произойдет, если вы попытаетесь интерпретировать эти байты как символы (на входе) или если вы пробовал записывать символы в байт-ориентированный поток. Я обновлю свой ответ, чтобы прояснить этот момент. - person Ted Hopp; 22.10.2017