黑马程序员技术交流社区

标题: 字符流的出现 [打印本页]

作者: 杨波    时间: 2012-3-11 20:00
标题: 字符流的出现
听老师的视频后,总结出字符流的出现,是为了解决对文本处理中因不同编码表造成的乱码问题。总感觉字符流功能不止于此,是不是还有其他作用?
作者: 杨波    时间: 2012-3-11 20:06
如果只是如此,把指定编码表的功能集成到字节流中,不就行了。
作者: 王睿    时间: 2012-3-11 20:40
指定编码表是转换流的功能吧,就是为了操作文件更方便点吧,暂时没发现其他功能
作者: 付鹏    时间: 2012-3-11 21:33
字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节, 操作字节和字节数组。所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好!如果是 音频文件、图片、歌曲,就用字节流好点,如果是关系到中文的,用字符流好点.

所有文件的储存是都是字节(byte)的储存,在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。在读取文件(特别是文本文件)时,也是一个字节一个字节地读取以形成字节序列.

字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串 字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以。
作者: baypm_jy    时间: 2012-3-11 22:21
可以使用流 访问文件系统上的文件。在最低的级别上,流允许程序接收来自数据源的字节,或者允许将输出发送到目的地。一些流可以处理所有类型的 16 位字符(类型 Reader 和 Writer)。而其他一些流则只能处理 8 位字符(类型 InputStream 和 OutputStream)。在这些分层结构中,有几种风格的流(所有流都可以在 java.io 包中找到)。在最高级别的抽象中,有一些字符流 和字节流。字节流读取(InputStream 及其子类)并编写(OutputStream 及其子类)8 位字节。换句话说,可以将字节流看作是一种更原始的流。因此,也就不难理解为什么关于基本 Java 语言类的 Java.sun.com 教程说字节流通常用于二进制数据,比如说图像。以下是一个选定的字节流列表:FileInputStream 从某一文件中读取文件FileOutputStream 将字节写入某个文件中。ByteArrayInputStream ByteArrayOutputStream从某个内存数组中
作者: 魏昂    时间: 2012-3-12 09:50
12.1.9  Java中的应用-I/O字节流到字符流的适配器(对象的适配器模式)

Java I/O最关键的4个类是InputStream(输入字节流)、OutputStream(输出字节流)、Reader(输入字符流)、Writer(输出字符流),它们都是public abstract class类。

InputSream和OutputStream对于数据的传送是以字节Byte为单位的,而Reader和Writer对于数据的传送是以字符Character为单位的。所以我们看到java.io包中的类大体上可以分为两大类,一类是以Byte处理为主的Stream类,它们都是以XXXStream方式命名的;一类是以Character处理为主的Reader/Writer类,它们都是以XXXReader或XXXWriter的方式命名的。

表12-1展示了InputStream、OutputStream、Reader、Writer的各种实现的子类。可以分为3类:数据源类、数据流串联类、数据流过滤类。其中的数据源类是创建各种流的起始类,第二类和第三类都是对各自流实例的包装。

表12-1  输入/输出流类列表


输入字节流
输出字节流
输入字符流
输出字符流

抽象类
InputStream
OutputStream
Reader
Writer

转换类
  
  
InputStreamReader
OutputStreamWriter

第一类:数据源类

数组
ByteArrayInputStream
ByteArrayOutputStream
CharArrayReader
CharArrayWriter

文件
FileInputStream
FileOutputStream
FileReader
FileWriter

对象
ObjectInputStream
ObjectOutputStream
  
  

字符串
StringBufferInputStream
  
StringReader
StringWriter

第二类:数据流串联类

管道
PipeInputStream
PipeOutputStream
PipedReader
PipeWriter

序列
SequenceInputStream
  
  
  

第三类:数据流过滤类

过滤
FilterInputStream
FilterOutputStream
FilterReader
FilterWriter

缓冲
BufferedInputStream
BufferedOutputStream
BufferedReader
BufferedWriter

数据
DataInputStream
DataOutputStream
  
  

行号
LineNumberInputStream
  
LineNumberReader
  

推回
PushbackInputStream
  
PushbackReader
  

格式化
  
PrintStream
  
PrintWriter



关于该表中各种类及其原理的使用,详细参见《Java高手真经-Java核心编程技术》一书。

从上表可以看出,以字符为导向的reader/writer基本上有与之相对应的以字节为导向的stream。两个对应类实现的功能相同,只是在操作时的导向不同。如 CharArrayReader和ByteArrayInputStream的作用都是把内存中的一个缓冲区作为流使用,所不同的是前者每次从内存中读取一个字节的信息,而后者每次从内存中读取一个字符。

然而,字节流与字符流之间的区别却可以联系起来,这就是表中的两个类InputStreamReader和OutputStreamReader。InputStreamReader负责把字节输入流转换为字符输入流,OutputStreamReader负责把输出字节流转换为输出字符流。下面来看看如何进行转换。

1.字节输入流转换为字符输入流

InputStreamReader是字节流通向字符流的桥梁,它使用指定的charset读取字节并将其解码为字符。它拥有一个InputStream类型的变量,并继承了Reader,使用了对象的适配器模式,如图12-9所示。

   


根据InputStream的实例创建InputStreamReader的方法有4种:

InputStreamReader(InputStream in);                //根据默认字符集创建  InputStreamReader(InputStream in, Charset cs);        //使用给定字符集创建  InputStreamReader(InputStream in, CharsetDecoder dec);    //使用给定字符集解码器创建  InputStreamReader(InputStream in, String charsetName);    //使用指定字符集创建 后面的3个构造函数都指定了一个字符集,最后一个是最简单的,可以直接指定字符集的名称来创建,例如GB2312等。

每次调用InputStreamReader中的一个read()方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。共有3个可用的read()方法:

int read();                               //读取单个字符  int read(char[] cbuf, int offset, int length);            //将字符读入数组中的某一部分  boolean ready();                              //判断此流是否已经准备好用于读取 InputStreamReader继承自Reader,因此该类的实例可以被各种输入字符流包装。为了达到最高效率,可以考虑在BufferedReader内包装InputStreamReader。例如程序12-20所示,我们首先创建了一个FileInputStream类的实例,然后转换为InputStreamReader对象is,最后使用BufferedReader进行包装。这样就可以将字节流转换为带缓冲功能的字符流。

程序12-20  TestInputStreamReader.java

public class TestInputStreamReader {      public static void main(String[] args) {          try {  // 创建输入流  FileInputStream fis = new FileInputStream("D:/demo/test.txt");  InputStreamReader is = new InputStreamReader(fis);  BufferedReader bis = new BufferedReader(is);   // 从输入流读取数据  while (bis.ready()) {      int c = bis.read();      System.out.print((char)c);  }   // 关闭输入流  bis.close();  is.close();  fis.close();          } catch (IOException e) {          }      }  } 2.字节输出流转换为字符输出流

OutputStreamWriter是字符流通向字节流的桥梁,可使用指定的charset将要写入流中的字符编码成字节。因此,它拥有一个OutputStream类型的变量,并继承了Writer,使用了对象的适配器模式,如图12-10所示。

   



根据OutputStream的实例创建OutputStreamWriter的方法有4种:

OutputStreamReader(OutputStream out);                     //根据默认字符集创建  OutputStreamReader(OutputStream out, Charset cs);                 //使用给定字符集创建  OutputStreamReader(OutputStream out, CharsetDecoder dec);         //使用给定字符集解码器创建  OutputStreamReader(OutputStream out, Stroutg charsetName);        //使用指定字符集创建 后面的3个构造函数都制定了一个字符集,最后一个是最简单的,可以直接指定字符集的名称来创建,例如GB2312等。

每次调用write()方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得到的这些字节将在缓冲区中累积。可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够大。注意,传递给write()方法的字符没有缓冲。共有3个可用的write()方法:

void write(char[] cbuf, int off, int len);//写入字符数组的某一部分  void write(int c);//写入单个字符  void write(String str, int off, int len);//写入字符串的某一部分 OutputStreamWriter继承自Writer,因此该类的实例可以被各种输出字符流包装。为了达到最高效率,可以考虑在BufferedWriter内包装OutputStreamWriter。例如程序12-21所示,我们首先创建了一个FileOutputStream类的实例,然后转换为OutputStreamReader对象os,最后使用BufferedWriter进行包装。这样就可以将字节流转换为带缓冲功能的字符流。






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2