两个进程间通过网络传输字符串
在计算机底层传输的只有形如
01011101
这种数字,1字节是由8位bit组成,而字符则是在某种字符集下字节的表现形式,最终都是通过一串01数字表达。当我们谈论字符而忽略字符集时是完全没有意义的,之所以有时不用去关心字符集是因为平台往往是有个默认的字符集。所以在传输字符的时候,发送方和接收方必须要事先约定好字符集。
下面的例子摘自《Java特种兵》书籍的第四章
例如发送2个汉字,用UTF-8编码发送后会占用6个字节,对方若知道传来的数据是UTF-8编码,便知道这6个字节代表什么汉字,就自然能正确得到char字符了。但是如果对方用GBK来编码,则可能会认为有3个字符,若按照每2个字节计算一个字符,得到的3个字符自然不是需要传递的2个汉字字符。假如此时意识到自己的编码错误了,通过得到的3个字符的字符串调用get-Byte(“GBK”)还可以还原6个字节,然后通过这6个字节再用new String(byte[],“UTF-8”)得到实际的两个汉字。真的是这样吗?要知道这是偶然的,不是必然的,因为UTF-8转换出来的6个字节,当按照每2个字节组成编码时,这个编码未必在GBK的编码范围内,若不在GBK的编码范围内,就可能会用一个“?”或其他字符来代表,由于“?”本身也是一个字符,当再次调用get-Byte(“GBK”)时得到的对应字节就是“?”对应的字节,而不是原来字符的字节,有可能都不再是6个字节了。换句话说,这样的情况是永远无法转换回来的。
字节流和字符流的关系
Reader/Writer内在的实现是通过sun.nio.cs.StreamDecoder、sun.nio.cs.StreamEn-coder来对字符集进行处理,最终还是通过字节来完成发送和接收的。
read()的小疑惑
InputStream.read()
方法返回一个int值,表示从流中读取的一个字节。我们知道byte类型的取值范围是:-128到127,但是read方法返回值的范围是0 - 255(另外返回-1表示流中没有可读字节)。
为什么要这样设计呢?其中一个原因是因为字符集的码表都是用非负数来表示的。
那如何进行转换呢?在BufferedInputStream
中,其read()方法是这样写的
public synchronized int read() throws IOException {
if (pos >= count) {
fill();
if (pos >= count)
return -1;
}
return buf[pos++] & 0xff;
}
其中buf是byte数组,可以看到通过buf[pos++] & 0xff
将字节的范围转移到0 - 255。
按用途分类流
字节输入流 | 字节输入流 | 字符输入流 | 字符输出流 | |
---|---|---|---|---|
基础 | InputStream | OutputStream | Reader InputStreamReader | Writer OutputStreamWriter |
数组 | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter |
文件 | FileInputStream RandomAccessFile | FileOutputStream RandomAccessFile | FileReader | FileWriter |
网络 | SocketInputStream URL HttpURLConnection Socket | SocketOutputStream URL HttpURLConnection Socket | ||
管道 | PipedInputStream | PipedOutputStream | PipedReader | PipedWriter |
缓冲 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
Filtering | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter |
解析 | PushbackInputStream StreamTokenizer | PushbackReader LineNumberReader | ||
String | StringReader | StringWriter | ||
Data | DataInputStream | DataOutputStream | ||
格式 | PrintStream | PrintWriter | ||
序列化 | ObjectInputStream | ObjectOutputStream | ||
Utilities | SequenceInputStream LineNumberInputStream | LineNumberReader |
扩展阅读
Java IO Tutorial