Пожалуйста, помогите мне прояснить некоторые понятия с Java IO и, возможно, влюбиться в него! - PullRequest
3 голосов
/ 29 марта 2011

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

public static void main(String[] args) throws IOException {
    String str = "English is being IOed!\nLine 2 has a number.\n中文字體(Chinese)";

    FileOutputStream fos = new FileOutputStream("ByteIO.txt");
    Scanner fis = new Scanner(new FileInputStream("ByteIO.txt"));
    FileWriter fw = new FileWriter("CharIO.txt");
    Scanner fr = new Scanner(new FileReader("CharIO.txt"));

    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("BufferedByteIO.txt"));
    Scanner bis = new Scanner(new BufferedInputStream(new FileInputStream("BufferedByteIO.txt")));
    BufferedWriter bw = new BufferedWriter(new FileWriter("BufferedCharIO.txt"));
    Scanner br = new Scanner(new BufferedReader(new FileReader("BufferedCharIO.txt")));

    DataOutputStream dos = new DataOutputStream(new BufferedOutputStream((new FileOutputStream("DataBufferedByteIO.txt"))));
    Scanner dis = new Scanner(new DataInputStream(new BufferedInputStream((new FileInputStream("DataBufferedByteIO.txt")))));

    try {
        System.out.printf("ByteIO:\n");
        fos.write(str.getBytes());
        while (fis.hasNext())
            System.out.print(fis.next());// in the form of a String

        System.out.printf("\nCharIO:\n");
        fw.write(str);
        while (fr.hasNext())
            System.out.print(fr.next());

        System.out.printf("\nBufferedByteIO:\n");
        bos.write(str.getBytes());
        bos.flush();// buffer is not full, so you'll need to flush it
        while (bis.hasNext())
            System.out.print(bis.next());

        System.out.printf("\nBufferedCharIO:\n");
        bw.write(str);
        bw.flush();// buffer is not full, so you'll need to flush it
        while (br.hasNext())
            System.out.print(br.next());

        System.out.printf("\nDataBufferedByteIO:\n");
        dos.write(str.getBytes());
        //dos.flush();// dos doesn't seem to need this...
        while (dis.hasNext())
            System.out.print(dis.next());
    } finally {
        fos.close();
        fis.close();
        fw.close();
        fr.close();
        bos.close();
        br.close();
        dos.close();
        dis.close();
    }

}

Все, что он делает, - это просто пишет предварительноопределенную строку в файл, а затем прочитать его.Проблема возникает, когда я запускаю код, я получаю это:

ByteIO:
EnglishisbeingIOed!Line2hasanumber.中文字體(Chinese)
CharIO:
                        //<--Empty line here
BufferedByteIO:
EnglishisbeingIOed!Line2hasanumber.中文字體(Chinese)
BufferedCharIO:
EnglishisbeingIOed!Line2hasanumber.中文字體(Chinese)
DataBufferedByteIO:
                        //<--Empty line here
  1. Все файлы заполнены правильными данными, поэтому я предполагаю, что что-то не так со сканером, но япросто не знаю, что пошло не так, и я надеюсь, что кто-то может указать мне на ошибку.

  2. Все файлы заполнены одинаковыми данными.Это странно, согласно Java I / O Streams , байтовые потоки могут обрабатывать только отдельные байты, и только символьные потоки могут обрабатывать Unicode, поэтому байтовые потоки не должны выплевывать бред при обработке китайских символов, которые являются UTF-16 (думаю)?Какая разница между байтовым потоком и символьным потоком (fos против fw)?

  3. По частично не связанной теме я думал, что потоки байтов использовались для работы с двоичными данными, такими как музыка и изображения, я также думал, что потоки байтов данных должны быть неразборчивы, ноКажется, я ошибаюсь?С какими именно классами потоков ввода-вывода мне следует работать, если я имею дело с двоичными данными?

Ответы [ 2 ]

4 голосов
/ 29 марта 2011

Здесь важно понять концепцию кодирования.

String / char[] / Writer / Reader используются для работы с текстовыми данными любого вида.

byte[] / OutputStream / InputStream используются для работы с двоичными данными.Кроме того, файл на вашем диске только каждый хранит двоичные данные (да, это правда, мы надеемся, что через минуту он станет немного более понятным).

Всякий раз, когда вы конвертируете между этими двумя мирами, будет использоваться какая-то кодировкав игре.В Java существует несколько способов преобразования между этими мирами без указания кодировки .В этом случае будет использоваться кодировка платформы по умолчанию (которая зависит от вашей платформы и конфигурации / локали).[*]

Задача кодирования - преобразовать некоторые заданные двоичные данные (обычно из byte[] / ByteBuffer / InputStream) в текстовые данные (обычно в char[] / CharBuffer/ Writer) или наоборот .

Как именно это происходит, зависит от используемой кодировки.Некоторые кодировки (такие как семейство ISO-8859- *) представляют собой простое сопоставление значений byte с соответствующими кодовыми точками Unicode, другие (такие как UTF-8) являются более сложными, и одна кодовая точка Unicode может быть любой от 1 до 4байт.

Есть довольно хорошая статья, которая дает общий обзор всей проблемы кодирования, озаглавленной: Абсолютный минимум, который должен знать каждый разработчик программного обеспечения о Unicode и наборах символов (никаких оправданий!)

[*] Использование кодировки по умолчанию на платформе обычно нежелательно, поскольку она делает вашу программу непереносимой и трудной в использовании, но это не относится к этому посту.

2 голосов
/ 29 марта 2011

Использование BufferedInputStream и DataInputStream не изменяет содержимое данных.

Поток байтов предназначен для чтения двоичных данных.Здесь это не подходит.

Поток символов предназначен для чтения текста, сканер предполагает, что вы читаете строки, оканчивающиеся новой строкой.(Которого у вас, похоже, нет)

Если я запускаю

String str = "English is being IOed!\nLine 2 has a number.\n\u4E2D\u6587\u5b57\u9ad4(Chinese)\n";
Writer fw = new OutputStreamWriter(new FileOutputStream("ReaderWriter.txt"), "UTF-8");
fw.write(str);
fw.close();
Reader fr = new InputStreamReader(new FileInputStream("ReaderWriter.txt"), "UTF-8");
Scanner scanner = new Scanner(fr);
String next = "";
while (scanner.hasNext()) {
    next = scanner.next();
    System.out.println(next);
}
for (int i = 0; i < next.length(); i++)
    System.out.println(Integer.toHexString((int) next.charAt(i)));
fr.close();

, я получаю

English
is
being
IOed!
Line
2
has
a
number.
????(Chinese)
4e2d
6587
5b57
9ad4
28
43
68
69
6e
65
73
65
29

Вы можете видеть, что оригинальные символы сохраняются.'?'означает, что символ не может быть отображен на моем терминале или в моей кодировке символов.(Не знаю почему)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...