请帮我用Java IO澄清一些概念,也许会爱上它!

时间:2011-03-29 12:22:25

标签: java io

我正在努力熟悉Java提供的不同类型的流IO,所以我在这里编写了这段代码。

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. 这些文件都填充了正确的数据,所以我认为扫描仪出了问题,但我不知道出了什么问题,我希望有人可以为我指出错误。< / p>

  2. 这些文件都填充了相同的数据。这很奇怪,根据Java I/O Streams,Byte Streams只能处理单个字节,而且只有Character Streams可以处理Unicode,因此Byte Streams在处理UTF-16(我认为)的中文字符时不会吐出乱码?字节流和字符流(fos vs fw)之间究竟有什么区别?

  3. 在一个部分不相关的主题上,我认为Byte Streams习惯使用二进制数据,如音乐和图像,我还认为Byte Streams吐出的数据应该难以理解,但我似乎错了,我呢?如果我处理二进制数据,我应该使用哪个I/O Stream Class(es)

2 个答案:

答案 0 :(得分:4)

这里要理解的一个重要概念是编码。

String / char[] / Writer / Reader用于处理任何类型的文字数据。

byte[] / OutputStream / InputStream用于处理二进制数据。此外,磁盘上的文件只存储二进制数据(是的,这是真的,希望在一分钟内更清晰)。

每当你在这两个世界之间进行转换时,某种编码就会发挥作用。在Java中,有几种方法可以在这些世界之间进行转换,而无需指定编码。在这种情况下,将使用平台默认编码(这取决于您的平台和配置/区域设置)。 [*]

编码的任务是将一些给定的二进制数据(通常从byte[] / ByteBuffer / InputStream)转换为文本数据(通常转换为char[] / { {1}} / CharBuffer或其他方式

如何完全这取决于所使用的编码。某些编码(例如ISO-8859- *系列)是从Writer值到相应的unicode代码点的简单映射,其他编码(例如UTF-8)更复杂,单个unicode代码点可以是1到4个字节。

有一篇非常好的文章,对整个编码问题进行了基本概述:The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

[*]通常不需要使用平台默认编码,因为它会使您的程序无法移植并且难以使用,但这不是本帖的重点。

答案 1 :(得分:2)

使用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

您可以看到保留原始字符。 '?'表示该字符无法显示在我的终端或我的字符编码上。 (我不知道为什么)