我正在努力熟悉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
这些文件都填充了正确的数据,所以我认为扫描仪出了问题,但我不知道出了什么问题,我希望有人可以为我指出错误。< / p>
这些文件都填充了相同的数据。这很奇怪,根据Java I/O Streams,Byte Streams只能处理单个字节,而且只有Character Streams可以处理Unicode,因此Byte Streams在处理UTF-16(我认为)的中文字符时不会吐出乱码?字节流和字符流(fos vs fw)之间究竟有什么区别?
在一个部分不相关的主题上,我认为Byte Streams习惯使用二进制数据,如音乐和图像,我还认为Byte Streams吐出的数据应该难以理解,但我似乎错了,我呢?如果我处理二进制数据,我应该使用哪个I/O Stream Class(es)?
答案 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
您可以看到保留原始字符。 '?'表示该字符无法显示在我的终端或我的字符编码上。 (我不知道为什么)