7.4过滤流与包装类-7.5IO中的高级应用

对 IO 进行缓冲是一种常见的性能优化。缓冲流为 IO 流增加了内存缓冲区。增加缓冲区有两个基本目的:
        允许 Java 的IO 一次不只操作一个字节,这样提高了整个系统的性能
        出于有缓冲区,使得在流上执行 skip、mark 和reset 方法都成为可能。
        BufferedInputStream
        Java的BufferedInputStream类可以对任何的InputStream进行带缓冲区的封装以达到性能的改善。BufferedInputStream 有两个构造函数:
                BufferedInputStream(InputStream in)
                BufferedInputStream(InputStream in,int size)

第一种形式的构造函数创建了一个带有 32 字节缓冲区的缓冲流,第二种形式的构造函数按指定的大小来创建缓冲区。通常缓冲区大小是内存、磁盘扇区或其他系统容量的整数倍,这样就可以充分提高 I/O 的性能。一个最优的缓冲区的大小,取决于它所在的操作系统、可用的内存空间以及机器的配置
对输入流进行缓冲可以实现部分字符的回流。除了 InputStream 中常用的 read 和 skip方法,BufferedInputStream 还支持mark 和reset 方法。mark 方法在流的当前位置作一个标记,该方法接收的一个整数参数用来指定从标记处开始,还能通过 read 方法读取的字节数reset 方法可以让以后的read 方法重新回到 mark 方法所作的标记处开始读取数据

mark 只能限制在建立的缓冲区内
        BufferedOutputStream
        往 BufferedOutputStream 输出和往 OutputStream 输出完全一样,只不过BufferedOutputStream 有一个 flush 方法用来将缓冲区的数据强制输出完。与缓冲区输入流不同,缓冲区输出流没有增加额外的功能。在 Java 中使用输出缓冲也是为了提高性能。它也有两个构造函数:
                BufferedoutputStream(OutputStream out)

                BufferedOutputStream(OutputStream out,int size)

字符的 UTF 编码对应下列规则:

        假如字符c的范围在u0001 和u007f 之间,对应的UTF 码占1个字节,内容为:(byte)c.
        假如字符c是u0000 或其范围在u0080和u07ff之间,对应的UTF码占2个字节内容为:(byte)(0xc0l(0x1f&(c>>6))),(byte)(0x801(0x3f&c))。
        假如字符c的范围在0800 和 uffff 之间,对应的UTF 码占3个字节,内容为:byte)0xe0l(0x0f&(c>>12))),(byte)0x801(0x3f &(c>>6))),(byte)0x801(0x3f&c))

import java.io.*;

public class DateStreamTest {
    public static void main(String[] args) {
        try {
            FileOutputStream fos = new FileOutputStream("hello.txt");
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            DataOutputStream dos = new DataOutputStream(bos);
            dos.writeUTF("ab中国");
            dos.writeBytes("ab中国");
            dos.writeChars("ab中国");
            dos.close();
            FileInputStream fis = new FileInputStream("hello.txt");
            BufferedInputStream bis = new BufferedInputStream(fis);
            DataInputStream dis = new DataInputStream(bis);
            System.out.println(dis.readUTF());
            fis.close();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
    }
}

PrintStream类提供了一系列的print和printin方法,可以实现将基本数据类型的格式化成字符串输出。在前面,我们在程序中大量用到“Systemoutprintin”语句中的Systemout就是PrintStream类的一个实例对象,读者已经多次使用到这个类了

println 方法与 print 方法的区别是:前者会在打印完的内容后再多打印一个换行符(n),所以println()等于print(“n")
Java的PrintStream对象具有多个重载的 print和println 方法,它们输出各种类型(包括Object)的数据。对于基本数据类型的数据,print和printn 方法会先将它们转换成字符串的形式后再输出,而不是输出原始的字节内容,如:整数 123 的打印结果是字符'1'  '3’所组合成的一个字符串,而不是整数 123 在内存中的原始字节数据。对于个非基本数据类型的对象,print和 println 方法会先调用对象的 toString 方法,然后再输出toString 方法返回的字符串
I0包中提供了一个与PrintStream对应的 PrintWriter类,PrintWriter 即使遇到换行符()也不会自动清空缓冲区,只在设置了autoflush 模式下使用了println方法后才自动清空缓冲区。PrintWriter 相对 PrintStream 最有利的一个地方就是 printIn 方法的行为,在 Windows的文本换行是“rin”,而 Liux 下的文本换行是“m”,如果我们希望程序能够生成平台相关的文本换行,而不是在各种平台下都用“m"作为文本换行,我们就应该使用 PrintWriter 的printIn方法时,PrintWriter的printIn方法能根据不同的操作系统而生成相应的换行符

格式化输出是指将一个数据用其字符串格式输出,如我们使用 print 方法把 97 这个整数打印到一个文件中,该方法将把“9’和“7’这两个字符的 ASCII 码写入到文件中,也就是文件中会被写入两个字节,这两个字节中的数字分别为 57(十六进制的 0x39)和 55(十六进制的0x37),在记事本程序中显示为“9’和“7’这两个字符。如果我们使用 write方法把97 这个整数写到一个文件中,只有一个字节会写入到这个文件中,字节中的数字就是97,正好是字符“a’的ASCII 码,所以在记事本程序中显示为一个字符“a’

序列化的好处在于:它可以将任何实现了 Serializable 接口的对象转换为连续的字节数据,这些数据以后仍可被还原为原来的对象状态,即使这些数据通过网络传输也没问题。序列化能处理不同操作系统上的差异,我们可以在 Windows 上产生某个对象,将它序列化存储,然后通过网络传到 Linux 机器上,该对象仍然可以被正确重建出来,在这期间,我们完全不用担心不同机器上的不同的数据表示方式

import java.io.*;

public class Serializatioan {
    public static void main(String[] args) throws IOException,ClassNotFoundException {
        Student stu = new Student(19, "dintdding", 50, "huaxue");
        FileOutputStream fos = new FileOutputStream("mytext.txt");
        ObjectOutputStream os = new ObjectOutputStream(fos);
        try {
            os.writeObject(stu);
            os.close();
        }catch (IOException e){
            System.out.println(e.getMessage());
        }
        stu=null;
        FileInputStream fi = new FileInputStream("mytext.txt");
        ObjectInputStream si = new ObjectInputStream(fi);
        try {
            stu=(Student)si.readObject();
            si.close();
        }catch (IOException e){
            System.out.println("ID is:"+stu.id);
            System.out.println("name is:"+stu.name);
            System.out.println("age is:"+stu.age);
            System.out.println("department is:"+stu.department );
        }
    }
}
class Student implements Serializable{
    int id;
    String name;
    int age;
    String department;

    public Student(int id, String name, int age, String department) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.department = department;
    }
}

InputStreamReader 和OutputStreamWriter,这两个类是字节流和字符流之间转换的类  InputStreamReader可以将一个字节流中的字节解码成字符,OuputStreamWriter将写入的字符编码成字节后写入一个字节流。
InputStreamReader 有两个主要的构造函数
        InputStreamReader(InputStream in)
                        //用默认字符集创建一个 InputstreamReader 对象

        InputStreamReader(InputStream in,String CharsetName)
                        /*接受以指定字符集名的字符串,并用该字符集创建对象*/

        OutputstreamWriter 也有对应的两个主要的构造函数

                OutputStreamWriter(Outputstream in)
                                //用默认字符集创建一个OutputstreamWriter对象                       OutputStreamWriter(OutputStream in,String CharsetName)

                                /*接受以指定字符集名的字符串,并用该字符集创建OutputStreamwriter 对象*/

构建 BufferedReader 对象时,必须传递一个Reader类型的对象作为参数,而键盘对应的Systemin是一个InputStream类型的对象,解决问题的关键是,我们还需要找到将InputStream类型的流对象包装成 Reader 类型的包装类

 

 

 

public class CharCode {
    public static void main(String[] args) throws Exception{
        System.getProperties().put("file.encoding","iso8859-1");
        System.getProperties().list(System.out);
        String strChina="中国";
        for (int i = 0; i < strChina.length(); i++) {
            System.out.println(Integer.toHexString((int)strChina.charAt(i)));
        }
        byte[] buf = strChina.getBytes();
        for (int i = 0; i < buf.length; i++) {
            System.out.println(Integer.toHexString(buf[i]));
        }
        System.out.println(strChina);
        for (int i = 0; i < buf.length; i++) {
            System.out.write(buf[i]);
        }
        System.out.println();
    }
}
import java.io.*;

public class CharDecoder {
    public static void main(String[] args) throws Exception{
		System.getProperties().put("file.encoding","iso8859-1");
        System.out.println("please enter a Chinese String:");
        byte[] buf = new byte[1024];
        int ch=0;
        int pos=0;
        String strInfo=null;
        while (true){
            ch=System.in.read();
            System.out.println(Integer.toHexString(ch));
            switch (ch){
                case 'r':
                    break;
                case 'n':
                    strInfo = new String(buf, 0, pos);
                    for (int i = 0; i < strInfo.length(); i++) {
                        System.out.println(Integer.toHexString((int)strInfo.charAt(i)));
                    }
                    System.out.println(strInfo);
                    for (int i = 0; i < pos; i++) {
                        System.out.write(buf[i]);
                        System.out.println();
                        return;
                    }
                default:
                    buf[pos++]=(byte)ch;
            }
        }
    }
}

字节用于表示计算机内存中最原始的数据,不会涉及到编码问题,只有把字节中的内容当做字符来处理时,才会涉及编码问题,所以 IputStreamReader、InputStreamWriter、PrintStream、String 中都有一个可以指定字符集编码参数的构造函数,而Inputstream的构
造函数中则不存在这样的参数。默认的情况下,如果你构造与流相连的 Reader和 Writer,字节和字符之间的转换规则使用默认的平台字符编码和 Unicode,比如在英语国家字节码是用ISO8859-1,用户也可以指定编码格式,具体的格式参考SUN公司的JDK文档首页中的Interationalization超链接部分,在JDK 文档首页中,你还能看到有关Java 的各种特性讲解的超链接,有空进去看看定会让你受益匪浅

其中Java 2 Platform APISpecification 部分就是JDK 中提供的各种类的帮助文档,Java程序员在实际编码的过程中会经常来查阅这一部分,但作者现在使用 FAllimant 整理成的chm 格式的文档,也就是我们前面多次使用的那个帮助系统,会更方便,更有效。我们再来看看为InputStreamReader 指定其他字符集参数,也就是用ISO8859-1替代默认的 GB2312 字符集

import java.io.*;

public class InputReader {
    public static void main(String[] args) throws Exception{
        InputStreamReader isr = new InputStreamReader(System.in, "iso8859-1");
        BufferedReader br = new BufferedReader(isr);
        String strLine = br.readLine();
        for (int i = 0; i < strLine.length(); i++) {
            System.out.println(Integer.toHexString((int)strLine.charAt(i)));
        }
        isr.close();
        System.out.println(strLine);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值