来源:http://java-mzd.javaeye.com/blog/801698
难道这两天不是特别忙
静下心来复习复习JAVA基础
抽空好好回顾了下IO方面的知识
主要是关于字节流与字符流的一个总结
字节流
顾名思义
以字节为单位进行IO操作
最大的两个父类是
InputStream与OutputStream
都是抽象类
需要通过多态
初始化具体实现的子类来进行读写操作
字符流
顾名思义
是以字符为单位进行IO操作的
一个字符为两个字节
最大的两个父类为
Writer和Reader这两个抽象类
当就字节流与字符流抽象类中的方法来看
其实方法名,返回值类型等都很相似
只是在传入参数部分
字节流的write()方法需要传入的是字节数组
字符流的write()方法需要传入的是字符数组(String也算字符数组?)
但是我们都知道字符数组和字节数组是很容易通过getBytes()和new String()来互换的
字节流和字符流的根本区别显然不在此处
那么到底字节流和字符流的主要区别是什么呢?
一.字节流在操作时不会用到缓冲区(内存),是直接对文件本身进行操作的。而字符流在操作时使用了缓冲区,通过缓冲区再操作文件。
二.在硬盘上的所有文件都是以字节形式存在的(图片,声音,视频),而字符值在内存中才会形成。
上面两点能说明什么呢?
针对第一点,
我们知道,如果一个程序频繁对一个资源进行IO操作,效率会非常低。此时,通过缓冲区,先把需要操作的数据暂时放入内存中,以后直接从内存中读取数据,则可以避免多次的IO操作,提高效率
针对第二点,
真正存储和传输数据时都是以字节为单位的,字符只是存在与内存当中的,所以,字节流适用范围更为宽广
三。字符流其实是通过转换流变化为字节流再进行IO操作
我们知道Reader和Writer都是抽象类,要进行具体的操作,都需要通过多态,利用具体实现的类中具体实现的方法进行操作
比如,我们适用字符流向文件中写入字符串,可能的代码如下
Java代码 import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; public class WriterTest { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub try { File f=new File("E:"+File.separator+"test.txt"); Writer writer=new FileWriter(f); writer.write("Hello World"); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; public class WriterTest { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub try { File f=new File("E:"+File.separator+"test.txt"); Writer writer=new FileWriter(f); writer.write("Hello World"); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }查看FileWriter源码
Java代码 package java.io; public class FileWriter extends OutputStreamWriter { public FileWriter(String fileName) throws IOException { super(new FileOutputStream(fileName)); } public FileWriter(String fileName, boolean append) throws IOException { super(new FileOutputStream(fileName, append)); } public FileWriter(File file) throws IOException { super(new FileOutputStream(file)); } public FileWriter(File file, boolean append) throws IOException { super(new FileOutputStream(file, append)); } public FileWriter(FileDescriptor fd) { super(new FileOutputStream(fd)); } } package java.io; public class FileWriter extends OutputStreamWriter { public FileWriter(String fileName) throws IOException { super(new FileOutputStream(fileName)); } public FileWriter(String fileName, boolean append) throws IOException { super(new FileOutputStream(fileName, append)); } public FileWriter(File file) throws IOException { super(new FileOutputStream(file)); } public FileWriter(File file, boolean append) throws IOException { super(new FileOutputStream(file, append)); } public FileWriter(FileDescriptor fd) { super(new FileOutputStream(fd)); } }可以轻松发现
FileWriter并非直接是Writer的子类,而是转换流OutputWriter的子类
FileWriter做的唯一的事:就是根据文件名,得到一个OutputStream,然后通过调用父类的构造器传入转换流OutputWriter中
继续查看OutputWriter中代码
Java代码 package java.io; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import sun.nio.cs.StreamEncoder; public class OutputStreamWriter extends Writer { private final StreamEncoder se; public OutputStreamWriter(OutputStream out, String charsetName) throws UnsupportedEncodingException { super(out); if (charsetName == null) throw new NullPointerException("charsetName"); se = StreamEncoder.forOutputStreamWriter(out, this, charsetName); } public void write(String str, int off, int len) throws IOException { se.write(str, off, len); } } package java.io; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import sun.nio.cs.StreamEncoder; public class OutputStreamWriter extends Writer { private final StreamEncoder se; public OutputStreamWriter(OutputStream out, String charsetName) throws UnsupportedEncodingException { super(out); if (charsetName == null) throw new NullPointerException("charsetName"); se = StreamEncoder.forOutputStreamWriter(out, this, charsetName); } public void write(String str, int off, int len) throws IOException { se.write(str, off, len); } }我们发现:
在转换流中,其实只是通过传入需要转换的字节流来构造一个StreamEncoder类对象
然后调用此StreamEncoder类对象se来完成write()方法,通过字节流输出
以上只分析了输出流,显然,对于输入流,道理是相同的
------------------------------------------------------------------------------------
字节流与字符流主要的区别是他们的的处理方式 字节流是最基本的,所有的InputStream和OutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的 但实际中很多的数据是文本,又提出了字符流的概念,它是按虚拟机的encode来处理,也就是要进行字符集的转化 这两个之间通过 InputStreamReader,OutputStreamWriter来关联,实际上是通过byte[]和String来关联 在实际开发中出现的汉字问题实际上都是在字符流和字节流之间转化不统一而造成的 在从字节流转化为字符流时,实际上就是byte[]转化为String时, public String(byte bytes[], String charsetName) 有一个关键的参数字符集编码,通常我们都省略了,那系统就用操作系统的lang 而在字符流转化为字节流时,实际上是String转化为byte[]时, byte[] String.getBytes(String charsetName) 也是一样的道理 至于java.io中还出现了许多其他的流,按主要是为了提高性能和使用方便, 如BufferedInputStream,PipedInputStream等