字符流总结--Day21

转换流出现的原因及思想
由于字节流操作中文不是特别方便,所以,java就提供了转换流(InputStreamReader,OutputStreamWriter)。
OutputStreamWriter:是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。
InputStreamReader:是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。
把字节流转换为字符流。
字符流=字节流+编码表。


究竟什么时候采用字节流,什么时候采用字符流?
能够用系统记事本打开并能阅读里面内容时,我们采用字符流,
否则,其他情况我们全部用字节流,注意,视频,应用软件等的复制吧不能使用字符流进行复制,因为字符流在提取字节码是进行编码,难免有所丢失,解码是也会发生状况,所以除了文本文件用字符流,其他文件全部用字节流

/*
 * 字节流读取中文可能出现的小问题:
 */
public class FileInputStreamDemo {
    public static void main(String[] args) throws IOException {
        // 创建字节输入流对象
        FileInputStream fis = new FileInputStream("a.txt");

        // 读取数据
        // int by = 0;
        // while ((by = fis.read()) != -1) {
        // System.out.print((char) by); //这里会输出单个字符,双字符的会变成乱码
        // }

        byte[] bys = new byte[1024];
        int len = 0;
        while ((len = fis.read(bys)) != -1) {
            System.out.print(new String(bys, 0, len));//这里不会出现乱码,因为他是整段读取,java会分析后判断属于字符还是字节,若像上面一样读取一个,还是会输出中文变乱码
        }

        // 释放资源
        fis.close();
    }
}


编码表
由字符及其对应的数值组成的一张表
常见编码表
计算机只能识别二进制数据,早期由来是电信号。
为了方便应用计算机,让它可以识别各个国家的文字。
就将各个国家的文字用数字来表示,并一一对应,形成一张表。

ASCII:美国标准信息交换码。
用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表
用一个字节的8位表示。
GB2312:中国的中文编码表。
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
GB18030:GBK的取代版本
BIG-5码 :通行于台湾、香港地区的一个繁体字编码方案,俗称“大五码”。
Unicode:国际标准码,融合了多种文字。
所有文字都用两个字节来表示,Java语言使用的就是unicode
UTF-8:最多用三个字节来表示一个字符。

UTF-8不同,它定义了一种“区间规则”,这种规则可以和ASCII编码保持最大程度的兼容:
它将Unicode编码为00000000-0000007F的字符,用单个字节来表示 它将Unicode编码为00000080-000007FF的字符用两个字节表示? 它将Unicode编码为00000800-0000FFFF的字符用3字节表示?


编码
把看得懂的变成看不懂的
解码
把看不懂的变成看得懂的

编码与解码例子,说明编码解码所用的编码表必须相同
public class Demo02 {
    // 编码与解码问题
    // String(byte[] bytes, String charsetName):通过指定的字符集解码字节数组
    // byte[] getBytes(String charsetName):使用指定的字符集合把字符串编码为字节数组
    //
    // 编码问题很难,难在编码与解码不一致会存在解析异常,不能尊却读取数据
    // 编码问题简单,只要编码解码的格式是一致的。
    public static void main(String[] args) throws UnsupportedEncodingException {
        String str = "你好";

        // 字符串到字节数组,称为编码,编码作用:更便于底层进行处理与存储
        // 本Eclipse的文本编辑器默认为GBK,可以设置改变
        // 下面进行编码:
        // ->
        byte[] by01 = str.getBytes();// 默认不写
        byte[] by02 = str.getBytes("GBK");// 设置为GBK
        byte[] by03 = str.getBytes("UTF-8");

        System.out.println(Arrays.toString(by01));
        System.out.println(Arrays.toString(by02));
        System.out.println(Arrays.toString(by03));

        // 以上结果输出
        // [-60, -29, -70, -61]
        // [-60, -29, -70, -61]
        // [-28, -67, -96, -27, -91, -67]

        // -----------------------------------------------

        // 下面进行解码
        // ->
        System.out.println(new String(by01));// 默认不写
        System.out.println(new String(by01, "GBK"));// GBK
        System.out.println(new String(by01, "UTF-8"));// UTF-8
        System.out.println();
        System.out.println(new String(by02));// 默认不写
        System.out.println(new String(by02, "GBK"));// GBK
        System.out.println(new String(by02, "UTF-8"));// UTF-8
        System.out.println();
        System.out.println(new String(by03));// 默认不写
        System.out.println(new String(by03, "GBK"));// GBK
        System.out.println(new String(by03, "UTF-8"));// UTF-8

        // 以上结果输出
        // 你好
        // 你好
        // ???
        //
        // 你好
        // 你好
        // ???
        //
        // 浣犲ソ
        // 浣犲ソ
        // 你好

        // -----------------------------------------------
    }
}

    字符(char)---获取对应字符整型(int)----按指定编码表编码-----得到编码表指向该字符的字节表示形式---保存该字节

    /*
     * OutputStreamWriter(OutputStream out):OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。
     * OutputStreamWriter(OutputStream out,String charsetName):根据指定编码把字节流数据转换为字符流
     * 把字节流转换为字符流。
     * 字符流 = 字节流 +编码表。
     */
    public static void main(String[] args) throws IOException {
        // 默认文本字符集GBK
        // OutputStreamWriter osw = new OutputStreamWriter(new
        // FileOutputStream("123.txt"));
        // osw.write("你好阳光,你好中国!");
        // osw.close();
        
        // 显式设定文本字符集:GBK
        // OutputStreamWriter osw = new OutputStreamWriter(new
        // FileOutputStream("123.txt"),"GBK");
        // osw.write("你好阳光,你好中国!");
        // osw.close();
        
        // 设定文本字符集:UTF-8
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
                "123.txt"), "UTF-8");
        osw.write("你好阳光,你好中国!");
        osw.close();
    }

    
    获取文件中的字节码---通过编码表将字节码解码转换为特定的整型(int)形式---将整型形式通过强制转换获得字符
    /*
     * InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。
     * InputStreamReader(InputStream is):用默认的编码读取数据
     * InputStreamReader(InputStream is,String charsetName):用指定的编码读取数据
     */
    public static void main(String[] args) throws IOException{
        //这是默认字符集:GBK
        InputStreamReader isr = new InputStreamReader(new FileInputStream("123.txt"));
        int ch = 0;//此处获取的是字符编码的int值,与inputStream中每次获取的字节数据不一样,这里是字符,分清字节字符区别
        while((ch=isr.read())!=-1){
            System.out.print((char)ch);//这里还是要强转,因为返回的是字符的整型(int)形态
        }
        isr.close();

        System.out.println("\n--------------------------\n");
        
        //这是指定字符集:GBK
        InputStreamReader isr02 = new InputStreamReader(new FileInputStream("123.txt"),"GBK");
        int ch02 = 0;//此处获取的是字符编码的int值,与inputStream中每次获取的字节数据不一样,这里是字符,分清字节字符区别
        while((ch02=isr02.read())!=-1){
            System.out.println("ch:"+ch02);
            //System.out.print((char)ch02);//这里还是要强转,因为返回的是字符的整型(int)形态
        }
        isr02.close();
        
        System.out.println("\n--------------------------\n");
        
        //这是指定字符集:GBK
        InputStreamReader isr03 = new InputStreamReader(new FileInputStream("123.txt"),"UTF-8");
        int ch03 = 0;//此处获取的是字符编码的int值,与inputStream中每次获取的字节数据不一样,这里是字符,分清字节字符区别
        while((ch03=isr03.read())!=-1){
            //System.out.println("ch:"+ch03);
            System.out.print((char)ch03);//这里还是要强转,因为返回的是字符的整型(int)形态
        }
        isr03.close();
        
        //    输出结果:注意,本来,该123.txt文本就是依照UTF-8的编码进行录入,所以前两个按照GBK形式阅读是没有办法解析的,因为UTF-8是三字节解析一个字符
        // 浣犲ソ闃冲厜锛屼綘濂戒腑鍥斤紒
        // --------------------------
        //
        // 浣犲ソ闃冲厜锛屼綘濂戒腑鍥斤紒
        // --------------------------
        //
        // 你好阳光,你好中国!
        //----------------------------------------------------------------------------
        // 在第三段代码while位置中添加:System.out.println("ch:"+ch03);可得字符的UTF-8整型表示形式
        // ch:20320
        // ch:22909
        // ch:38451
        // ch:20809
        // ch:65292
        // ch:20320
        // ch:22909
        // ch:20013
        // ch:22269
        // ch:65281
    }
    
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        char ch = '中';
        System.out.println((int)ch);   //输出结果:20013
    }
    
    
    
    /*
 * OutputStreamWriter的方法:
 * public void write(int c):写一个字符
 * public void write(char[] cbuf):写一个字符数组
 * public void write(char[] cbuf,int off,int len):写一个字符数组的一部分
 * public void write(String str):写一个字符串
 * public void write(String str,int off,int len):写一个字符串的一部分
 *
 * 注意以后操作字符流时候,由于字符流不是直接写道文件上,而是先放在缓冲区上缓冲,再执行刷新写入,而字节流文件看了会自动接收。
 *
 * 不执行close或flush操作时,字节依旧能写入到文件,因为他是不走缓冲的,而字符是双字节,先走缓冲再走写入,所以要刷新缓冲区,将字符码冲到文件中写入
 *
 * 面试题:close()和flush()的区别?
 * A:close()关闭流对象,但是先刷新一次缓冲区。关闭之后,流对象不可以继续再使用了。
 * B:flush()仅仅刷新缓冲区,刷新之后,流对象还可以继续使用。
 *
 * 最好不要每次写字符流都执行flush()方法,因为每一次写完字符,执行flush()方法,就会让方法从方法去送到栈去执行,然后执行完丢去,如果写入内容不是很多,但次数多,那么调用flush方法次数过多,方法整天进栈出栈,效率不高。最好是如果数据量不大,直接执行关闭方法就行,因为方法会自动刷新一次然后在关闭流。若文件真的很大,那么可以设定要一定的数据量时我们调用flush方法,减少调用flush方法次数。
 */
public class OutputStreamWriterDemo {
    public static void main(String[] args) throws IOException {
        // 创建对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
                "osw2.txt"));

        // 写数据
        // public void write(int c):写一个字符
        // osw.write('a');
        // osw.write(97);
        // 为什么数据没有进去呢?
        // 本次试验,我的关闭方法是没有写的,所以没有进去的第一个原因是没有没有关闭流,其实关闭操作也会进行一次刷新,将数据写道文件上。
        // 原因是:字符 = 2字节
        // 文件中数据存储的基本单位是字节。
        // 文件发现是字符的存入,所以就不会自动操作,所以我们需要手动执行flush()方法进行刷新,把缓冲推到他们该去的地方
        // void flush()

        // public void write(char[] cbuf):写一个字符数组
        // char[] chs = {'a','b','c','d','e'};
        // osw.write(chs);

        // public void write(char[] cbuf,int off,int len):写一个字符数组的一部分
        // osw.write(chs,1,3);

        // public void write(String str):写一个字符串
        // osw.write("我爱林青霞");

        // public void write(String str,int off,int len):写一个字符串的一部分
        osw.write("我爱林青霞", 2, 3);

        // 刷新缓冲区
        osw.flush();
        // osw.write("我爱林青霞", 2, 3);

        // 释放资源
        osw.close();
        // java.io.IOException: Stream closed
        // osw.write("我爱林青霞", 2, 3);
    }
}



/*
 * InputStreamReader的方法:
 * int read():一次读取一个字符
 * int read(char[] chs):一次读取一个字符数组
 */
public class InputStreamReaderDemo {
    public static void main(String[] args) throws IOException {
        // 创建对象
        InputStreamReader isr = new InputStreamReader(new FileInputStream(
                "StringDemo.java"));

        // 一次读取一个字符
        // int ch = 0;
        // while ((ch = isr.read()) != -1) {
        // System.out.print((char) ch);
        // }

        // 一次读取一个字符数组
        char[] chs = new char[1024];
        int len = 0;
        while ((len = isr.read(chs)) != -1) {
            System.out.print(new String(chs, 0, len));
        }

        // 释放资源
        isr.close();
    }
}



/*
 * 需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中
 *
 * 数据源:
 *         a.txt -- 读取数据 -- 字符转换流 -- InputStreamReader
 * 目的地:
 *         b.txt -- 写出数据 -- 字符转换流 -- OutputStreamWriter
 */
public class CopyFileDemo {
    public static void main(String[] args) throws IOException {
        // 封装数据源
        InputStreamReader isr = new InputStreamReader(new FileInputStream(
                "a.txt"));
        // 封装目的地
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
                "b.txt"));

        // 读写数据
        // 方式1
        // int ch = 0;
        // while ((ch = isr.read()) != -1) {
        // osw.write(ch);
        // }

        // 方式2
        char[] chs = new char[1024];
        int len = 0;
        while ((len = isr.read(chs)) != -1) {
            osw.write(chs, 0, len);
            // osw.flush();
        }

        // 释放资源
        osw.close();
        isr.close();
    }
}


/*
 * 由于我们常见的操作都是使用本地默认编码,所以,不用指定编码。
 * 而转换流的名称有点长,所以,Java就提供了其子类供我们使用。
 * OutputStreamWriter = FileOutputStream + 编码表(GBK)
 * FileWriter = FileOutputStream + 编码表(GBK)    用来写入字符文件的便捷类。默认字符集了
 *
 * InputStreamReader = FileInputStream + 编码表(GBK)
 * FileReader = FileInputStream + 编码表(GBK)      用来读取字符文件的便捷类。默认字符集了
 *
 /*
 * 需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中
 *
 * 数据源:
 *         a.txt -- 读取数据 -- 字符转换流 -- InputStreamReader --名字太长了,包装了一下-- FileReader
 * 目的地:
 *         b.txt -- 写出数据 -- 字符转换流 -- OutputStreamWriter --名字太长了,包装了一下-- FileWriter
 */
public class CopyFileDemo2 {
    public static void main(String[] args) throws IOException {
        // 封装数据源
        FileReader fr = new FileReader("a.txt");
        // 封装目的地
        FileWriter fw = new FileWriter("b.txt");

        // 一次一个字符
        // int ch = 0;
        // while ((ch = fr.read()) != -1) {
        // fw.write(ch);
        // }

        // 一次一个字符数组
        char[] chs = new char[1024];
        int len = 0;
        while ((len = fr.read(chs)) != -1) {
            fw.write(chs, 0, len);
            fw.flush();
        }

        // 释放资源
        fw.close();
        fr.close();
    }
}


/*
 * BufferedReader
 * 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
 * 可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
 *
 * BufferedReader(Reader in)
 */
public class BufferedReaderDemo {
    public static void main(String[] args) throws IOException {
        // 创建字符缓冲输入流对象
        BufferedReader br = new BufferedReader(new FileReader("bw.txt"));

        // 方式1
        // int ch = 0;
        // while ((ch = br.read()) != -1) {
        // System.out.print((char) ch);
        // }

        // 方式2
        char[] chs = new char[1024];
        int len = 0;
        while ((len = br.read(chs)) != -1) {
            System.out.print(new String(chs, 0, len));
        }

        // 释放资源
        br.close();
    }
}

/*
 * 字符流为了高效读写,也提供了对应的字符缓冲流。
 * BufferedWriter:字符缓冲输出流
 * BufferedReader:字符缓冲输入流
 *
 * BufferedWriter:字符缓冲输出流
 * 将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
 * 可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
 */
public class BufferedWriterDemo {
    public static void main(String[] args) throws IOException {
        // BufferedWriter(Writer out)
        // BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
        // new FileOutputStream("bw.txt")));

        BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));

        bw.write("hello");
        bw.write("world");
        bw.write("java");
        bw.flush();

        bw.close();
    }
}


/*
 * 字符缓冲流的特殊方法:
 * BufferedWriter:
 *         public void newLine():根据系统来决定换行符,不同的系统添加的换行都会不一样
 * BufferedReader:
 *         public String readLine():一次读取一行数据
 *         包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
 */
public class BufferedDemo {
    public static void main(String[] args) throws IOException {
        // write();
        read();
    }

    private static void read() throws IOException {
        // 创建字符缓冲输入流对象
        BufferedReader br = new BufferedReader(new FileReader("bw2.txt"));

        // public String readLine():一次读取一行数据
        // String line = br.readLine();
        // System.out.println(line);
        // line = br.readLine();
        // System.out.println(line);

        // 最终版代码
        String line = null;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
        
        //释放资源
        br.close();
    }

    private static void write() throws IOException {
        // 创建字符缓冲输出流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("bw2.txt"));
        for (int x = 0; x < 10; x++) {
            bw.write("hello" + x);
            // bw.write("\r\n");
            bw.newLine();
            bw.flush();
        }
        bw.close();
    }
}


九种读写文件方法:
字节流:四种
字符流:五种
-----------------------------------------------------------------------------------------------------
//字节流
/*
 * 复制图片
 *
 * 分析:
 *         复制数据,如果我们知道用记事本打开并能够读懂,就用字符流,否则用字节流。
 *         通过该原理,我们知道我们应该采用字节流。
 *         而字节流有4种方式,所以做这个题目我们有4种方式。推荐掌握第4种。
 *
 * 数据源:
 *         c:\\a.jpg -- FileInputStream -- BufferedInputStream
 * 目的地:
 *         d:\\b.jpg -- FileOutputStream -- BufferedOutputStream
 */
public class CopyImageDemo {
    public static void main(String[] args) throws IOException {
        // 使用字符串作为路径
        // String srcString = "c:\\a.jpg";
        // String destString = "d:\\b.jpg";
        // 使用File对象做为参数
        File srcFile = new File("c:\\a.jpg");
        File destFile = new File("d:\\b.jpg");

        // method1(srcFile, destFile);
        // method2(srcFile, destFile);
        // method3(srcFile, destFile);
        method4(srcFile, destFile);
    }

    // 字节缓冲流一次读写一个字节数组
    private static void method4(File srcFile, File destFile) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
                srcFile));
        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream(destFile));

        byte[] bys = new byte[1024];
        int len = 0;
        while ((len = bis.read(bys)) != -1) {
            bos.write(bys, 0, len);
        }

        bos.close();
        bis.close();
    }

    // 字节缓冲流一次读写一个字节
    private static void method3(File srcFile, File destFile) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
                srcFile));
        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream(destFile));

        int by = 0;
        while ((by = bis.read()) != -1) {
            bos.write(by);
        }

        bos.close();
        bis.close();
    }

    // 基本字节流一次读写一个字节数组
    private static void method2(File srcFile, File destFile) throws IOException {
        FileInputStream fis = new FileInputStream(srcFile);
        FileOutputStream fos = new FileOutputStream(destFile);

        byte[] bys = new byte[1024];
        int len = 0;
        while ((len = fis.read(bys)) != -1) {
            fos.write(bys, 0, len);
        }

        fos.close();
        fis.close();
    }

    // 基本字节流一次读写一个字节
    private static void method1(File srcFile, File destFile) throws IOException {
        FileInputStream fis = new FileInputStream(srcFile);
        FileOutputStream fos = new FileOutputStream(destFile);

        int by = 0;
        while ((by = fis.read()) != -1) {
            fos.write(by);
        }

        fos.close();
        fis.close();
    }
}
---------------------------------------------------------------------------------------------------------------
//字符流
/*
 * 复制文本文件
 *
 * 分析:
 *         复制数据,如果我们知道用记事本打开并能够读懂,就用字符流,否则用字节流。
 *         通过该原理,我们知道我们应该采用字符流更方便一些。
 *         而字符流有5种方式,所以做这个题目我们有5种方式。推荐掌握第5种。
 * 数据源:
 *         c:\\a.txt -- FileReader -- BufferdReader
 * 目的地:
 *         d:\\b.txt -- FileWriter -- BufferedWriter
 */
public class CopyFileDemo {
    public static void main(String[] args) throws IOException {
        String srcString = "c:\\a.txt";
        String destString = "d:\\b.txt";
        // method1(srcString, destString);
        // method2(srcString, destString);
        // method3(srcString, destString);
        // method4(srcString, destString);
        method5(srcString, destString);
    }

    // 字符缓冲流一次读写一个字符串
    private static void method5(String srcString, String destString)
            throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(srcString));
        BufferedWriter bw = new BufferedWriter(new FileWriter(destString));

        String line = null;
        while ((line = br.readLine()) != null) {
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        bw.close();
        br.close();
    }

    // 字符缓冲流一次读写一个字符数组
    private static void method4(String srcString, String destString)
            throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(srcString));
        BufferedWriter bw = new BufferedWriter(new FileWriter(destString));

        char[] chs = new char[1024];
        int len = 0;
        while ((len = br.read(chs)) != -1) {
            bw.write(chs, 0, len);
        }

        bw.close();
        br.close();
    }

    // 字符缓冲流一次读写一个字符
    private static void method3(String srcString, String destString)
            throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(srcString));
        BufferedWriter bw = new BufferedWriter(new FileWriter(destString));

        int ch = 0;
        while ((ch = br.read()) != -1) {
            bw.write(ch);
        }

        bw.close();
        br.close();
    }

    // 基本字符流一次读写一个字符数组
    private static void method2(String srcString, String destString)
            throws IOException {
        FileReader fr = new FileReader(srcString);
        FileWriter fw = new FileWriter(destString);

        char[] chs = new char[1024];
        int len = 0;
        while ((len = fr.read(chs)) != -1) {
            fw.write(chs, 0, len);
        }

        fw.close();
        fr.close();
    }

    // 基本字符流一次读写一个字符
    private static void method1(String srcString, String destString)
            throws IOException {
        FileReader fr = new FileReader(srcString);
        FileWriter fw = new FileWriter(destString);

        int ch = 0;
        while ((ch = fr.read()) != -1) {
            fw.write(ch);
        }

        fw.close();
        fr.close();
    }
}

posted @ 2015-07-08 22:53  暴走骑士  阅读(297)  评论(0编辑  收藏  举报