赞
踩
流是一个相对抽象的概念,所谓流就是一个传输数据的通道,这个通道可以传输相应类型的数据。进而完成数据的传输。这个通道被实现为一个具体的对象。
处理字节:InputStream OutputStream
处理字符:Reader Writer
Java中字符是以Unicode形式存储的,一个字符占用两个字节,然而InputStream和OutputStream都是以字节形式读取或写出数据的,会将一个字符拆分成两个字节来读写这样会造成乱码
在InputStream 和 Reader抽象类中都有一个抽象方法 abstract int read(),这个方法将会读入一个字节或字符,当到达输入数据块的末尾的时候返回-1,所有的输入流只要覆盖这个方法,完成具体的功能。
在OutputStream 和 Writer抽象类中都有一个抽象方法 abstract void write(int b),这个方法将会象某一个输出位置写一个字节或者字符。所有的输出流只覆盖这个方法,完成具体的输出功能。
read()和write()方法都是阻塞方法,当一个流不能被立即访问或者字节不能被成功的读出或写入的时候,当前线程将进入阻塞态直到字节确实被读入或者被写出。这样的设置保证了数据的安全性。
输入流与输出流层次结构
Reader和Writer的层次结构
对于西方来说,用不到字符,字节就够了。26个字母外加几个常用的符号。256个码位就够了。这就是我们常见的ASCII码表
西方世界不光英语,还有小语种。每个国家都可以定义属于自己语言的特殊编码标准,而且大小一样不超过256。因为ASCII码本身还有空位。所以就衍生出了ISO/IEC 8859-n国际标准化组织定义的一系列8位字符集。比如ISO/IEC 8859-1就是法语,芬兰语所用的西欧字符集。如下图。
在出现Unicode之前,几乎每一种文字都有一套自己的编码方式。同一段“字节流”,在美帝可能是"hello world",到我们天朝就变成“锟斤拷” ,“烫烫烫”了。所以“Unicode”可谓大势所趋。它的理念非常简单:全世界每个不同语言的不同字符都统一编码,全球通行。
最初,每个字符占用2个字节,总共65536(2的16次方,即一个字符)个字符空间。后来又了附加字符集。目前Unicode收录的字符规模大概在12万左右。
编码里最容易搞混的一件事就是:Unicode只是一套符号的编码。但计算机具体怎么读取这套编码,又是另外一件事。
比如既然Unicode常规字符集占用2个字节,系统可以每次老老实实读取两个字节。然后用一个特殊符号告诉系统某个字符属于附加字符集,需要再往后读2个字节。比如说Java系统默认的UTF-16就是就是这样编码解码的。
但上面UTF-16的缺点也很明显:就是所有英语字符“I am”也被迫用2个字节来编码。
考虑到英语是使用最广泛的语言,用2个字节为1字节信息编码,浪费了内存空间。最好是让英语保持ASCII的编码,用1个字节。汉字等其他字符才用2个或更长的字节表示。
这里就涉及到一个技术问题:怎么让系统知道一个字符是用1个还是2个还是3个字节编码的呢?这就是UTF-8做的事。
如下图所示,这里UTF-8可变长编码用到了一个小技巧:用几位冗余信息告诉系统,当前字符有没有结束,是不是还需要继续往下读下一个字节。
可以看到如果一个字节是以“0”开头的,说明是一个ASCII字符,只占一个字节。如果是“11”开头的,说明这个字符占用多个字节。后续每个“10”打头的字节都是这个字符的一部分。
总而言之,一切都是字节流,其实没有字符流这个东西。字符只是根据编码集对字节流翻译之后的产物。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。