java 字节流与字符流的区别

java 字节流与字符流的区别大致有两点

1、操作上的区别

  字节流在输出的时候不会使用缓冲区,而字符流会使用缓冲区,如下图所示

  

  下面以两个写文件的操作为主进行比较,但是在操作时字节流和字符流的操作完成之后都不关闭输出流。

  范例:使用字节流不关闭执行

import java.io.File;    
import java.io.FileOutputStream;    
import java.io.OutputStream;    
public class OutputStreamDemo05 {    
public static void main(String[] args) throws Exception {   // 异常抛出,  不处理    
// 第1步:使用File类找到一个文件    
     File f = new File("d:" + File.separator + "test.txt"); // 声明File  对象    
// 第2步:通过子类实例化父类对象    
     OutputStream out = null;            
// 准备好一个输出的对象    
     out = new FileOutputStream(f);      
// 通过对象多态性进行实例化    
// 第3步:进行写操作    
     String str = "Hello World!!!";      
// 准备一个字符串    
     byte b[] = str.getBytes();          
// 字符串转byte数组    
     out.write(b);                      
// 将内容输出    
 // 第4步:关闭输出流    
    // out.close();                  
// 此时没有关闭    
        }    
    }   

程序运行结果:

此时没有关闭字节流操作,但是文件中也依然存在了输出的内容,证明字节流是直接操作文件本身的。而下面继续使用字符流完成,再观察效果。

范例:使用字符流不关闭执行

import java.io.File;    
import java.io.FileWriter;    
import java.io.Writer;    
public class WriterDemo03 {    
    public static void main(String[] args) throws Exception { // 异常抛出,  不处理    
        // 第1步:使用File类找到一个文件    
        File f = new File("d:" + File.separator + "test.txt");// 声明File 对象    
        // 第2步:通过子类实例化父类对象    
        Writer out = null;                 
// 准备好一个输出的对象    
        out = new FileWriter(f);            
// 通过对象多态性进行实例化    
        // 第3步:进行写操作    
        String str = "Hello World!!!";      
// 准备一个字符串    
        out.write(str);                    
// 将内容输出    
        // 第4步:关闭输出流    
        // out.close();                   
// 此时没有关闭    
    }    
}  

程序运行结果:




程序运行后会发现文件中没有任何内容,这是因为字符流操作时使用了缓冲区,而   在关闭字符流时会强制性地将缓冲区中的内容进行输出,但是如果程序没有关闭,则缓冲区中的内容是无法输出的,所以得出结论:字符流使用了缓冲区,而字节流没有使用缓冲区。

需要 用flush将缓冲区的字符输出到文件

 

2、存储上的区别

用几个常用类型的数据来比较字节流和字符流的区别
int a=5; boolean b=true; char c='G'; String d="你好";
 
使用字符流打印以上类型的数据到文件中:
PrintWriter dos =new PrintWriter(new BufferedWriter(new FileWriter("c:\\buffertest.txt"))); dos.print(a); dos.print(b); dos.print(c); dos.print(d);
 
结果如下:
a是5
b是true
c是G
d是你好
字符流完全保证了和我们输入的字符保持一致
 
再看看字节流
DataOutputStream dos =new DataOutputStream(new FileOutputStream("c:\\streamtest.txt")); dos.writeInt(a); dos.writeBoolean(b); dos.writeChar(c); dos.writeUTF(d); dos.writeChars(d); dos.writeBytes(d);
 
结果是二进制文件,我们用十六进制编辑器打开它
a是00 00 00 05,int是四个字节
b是01,布尔型变量是一个字节
c是00 47,char是两个字节
d分别用3个不同的函数打印在文件中
第一个是00 06 E4 BD A0 E5 A5 BD,前面的00 06是writeUTF加上去的,是字节的数目,后面六个字节是"你好"的UTF编码,每个汉字3个字节
第二个是4F 60 59 7D,这是"你好"的big endian的Unicode编码,每个汉字2个字节
第三个是60 7D,这是从4F 60 59 7D中分别取得两个汉字的低字节
 
进一步说明
用记事本保存不同的编码文件,文件的头部会有一些标记来识别文件的编码类型,用记事本的另存为就可以保存不同编码类型的文件,然后用记事本打开时就可以正确识别编码,如果用十六进制编辑器打开它们就会看到用来识别编码类型的标记被写在文件头部,这些类型说明如下:
EF BB BF UTF-8 FF FE UTF-16/UCS-2, little endian FE FF UTF-16/UCS-2, big endian FF FE 00 00 UTF-32/UCS-4, little endian. 00 00 FE FF UTF-32/UCS-4, big-endian.
 
UTF-8保存一个字符时,长度为1-3个字节,也就是8bit-24bit。 其中code<= 007F的,保存为1个字节 (code >= 0080) && (code <= 0x07FF)的,保存为2个字节 code>0800的,保存为3个字节
"你好"的gb2312编码是C4 E3 BA C3,汉字大于0800,所以每个汉字保存为3个字节
 
little endian:低地址存放字节低位,x86是这种顺序 big endian:低地址存放字节高位,网络字节序是这种顺序
posted @ 2015-04-29 10:58  Maydow  阅读(170)  评论(0编辑  收藏  举报