Java-IO流(五)-字符流(OutputStreamWriter、InputStreamReader)

概述

字节--->字符 : 看不懂的--->看的懂的。  需要读。输入流。 InputStreamReader
字符--->字节 : 看的懂的--->看不懂的。  需要写。输出流。 OutputStreamWriter

OutputStreamWriter-指定编码写中文、InputStreamReader-指定编码读中文

OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;

public class TransStreamDemo {

    /**
     * @param args
     * @throws IOException 
     * @throws UnsupportedEncodingException 
     */
    public static void main(String[] args) throws Exception {
        
//      writeCN();
        
        readCN();
        /*
        总结:
        发现继承关系是这样的。
        OutputStreamWriter:
            |--FileWriter:
                
        InputStreamReader:
            |--FileReader;

        父类和子类的功能有什么区别呢?
        
        OutputStreamWriter和InputStreamReader是字符和字节的桥梁:也可以称之为字符转换流。
        字符转换流原理:字节流+编码表。
        
        FileWriter和FileReader:作为子类,仅作为操作字符文件的便捷类存在。
        当操作的字符文件,使用的是默认编码表时可以不用父类,而直接用子类就完成操作了,简化了代码。
        
        InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//默认字符集。
        InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字符集。
        FileReader fr = new FileReader("a.txt");
        这三句代码的功能是一样的,其中第三句最为便捷。
        
        注意:一旦要指定其他编码时,绝对不能用子类,必须使用字符转换流。
        什么时候用子类呢?
        条件:
        1,操作的是文件。
        2,使用默认编码。
        
        字节--->字符 : 看不懂的--->看的懂的。  需要读。输入流。 InputStreamReader
        字符--->字节 : 看的懂的--->看不懂的。  需要写。输出流。 OutputStreamWriter
        
        
        */
    }

    public static void readCN() throws IOException {//解码
        
        //创建InputStreamReader对象。
        InputStreamReader isr = new InputStreamReader(new FileInputStream("tempfile/u8cn.txt"),"UTF-8");
        
        char[] buf = new char[1024];
        int len = isr.read(buf);
        System.out.println(new String(buf,0,len));
        isr.close();
    }

    //读取中文。
    public static void readCN_no() throws IOException {
        
        // 使用FileReader没出来,因为文件是UTF-8编码。读取UTF-8字节时,用该指定用UTF-8解码。
        // 说明需要指定码表。那就需要使用InputStreamReader。
        FileReader fr = new FileReader("tempfile/u8cn.txt");
//      int ch = (char)fr.read();
//      System.out.println((char)ch);
        char[] buf = new char[1024];
        int len = fr.read(buf);
        System.out.println(new String(buf,0,len));//浣犲ソ

        
        fr.close();
        
    }

    public static void writeCN() throws Exception {//编码
        //需求:既然识别中文的码表有两个,GBK UTF-8
        //能不能将中文数据按照utf-8的方式进行文件的存储呢?
        //还能使用FileWriter吗?不能使用了,因为FileWriter中默认的是GBK
        //通过FileWriter的api描述,要指定编码表这些值,需要使用OutputStreamWriter 
        //OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。
        //它的作用的就是,将字符串按照指定的编码表转成字节,在使用字节流将这些字节写出去。
        
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("tempfile/u8cn.txt"),"utf-8");
        
        osw.write("你好");//写入缓冲区。
        
        osw.close();
    }

}
转换流的图解

字符流-复制文本文件

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyTextFileTest {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
        /*
         * 练习:复制文本文件。
         * 思路:
         * 1,既然是文本涉及编码表。需要用字符流。
         * 2,操作的是文件。涉及硬盘。
         * 3,有指定码表吗?没有,默认就行。
         * 操作的是文件,使用的 默认码表。使用哪个字符流对象。直接使用字符流操作文件的便捷类。FileReader  FileWriter
         */
        copyTextFile();
    }

    public static void copyTextFile() throws IOException {
        //1,明确源和目的。
        FileReader fr = new FileReader("Test24.java");
        FileWriter fw = new FileWriter("tempfile/test24_copy.txt");
        
        //2,为了提高效率。自定义缓冲区数组。字符数组。
        char[] buf = new char[1024];
        
        int len = 0;
        while((len=fr.read(buf))!=-1){
            fw.write(buf,0,len);
        }
        
        
        //2,循环读写操作。效率低。
//      int ch = 0;
//      while((ch=fr.read())!=-1){
//          fw.write(ch);
//      }
        
        //3,关闭资源。
        fw.close();
        fr.close();
        
    }

}

字符流-字符流缓冲区对象复制文本文件

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CharStreamBufferedTest {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
        /*
         * 字符流中是否有提供缓冲区中。
         * 注意:其实自定义数组就可以解决问题缓冲区问题并提高效率。
         * 为什么还要使用流中的缓冲区对象呢?因为缓冲区对象中除了封装数组以外,
         * 还提供了更多的操作缓冲区数据的方法。
         * BufferedReader  BufferedWriter
         * 
         * 讲解字符流缓冲区中的特有方法。
         * 操作字符数据时,有一个文本特有的表形实行 :行(hang)
         * 操作行的方法。
         * BufferedReader:readLine():一次读取一行。
         * BufferedWriter:
         */
        
        copyTextByBuffer();
//      readText();
        
//      writeText();
    }

    public static void writeText() throws IOException {
        BufferedWriter bufw = new BufferedWriter(new FileWriter("tempfile/test24_buf.txt"));
        
        for(int x=1; x<=4; x++){
            bufw.write(x+"-itcast");
            bufw.newLine();
            bufw.flush();
        }
        bufw.close();
    }

    public static void readText() throws IOException {
        
        BufferedReader bufr = new BufferedReader(new FileReader("Test24.java"));
        
        
        String line = null;
        while((line=bufr.readLine())!=null){
            
            System.out.println(line);
            
        }
        
//      String line = bufr.readLine();
//      System.out.println("-"+line+"-");
//      String line1 = bufr.readLine();
//      System.out.println("-"+line1+"-");
        
        bufr.close();
        
        
    }

    public static void copyTextByBuffer() throws IOException {
        
        BufferedReader bufr = new BufferedReader(new FileReader("Test24.java"));
        BufferedWriter bufw = new BufferedWriter(new FileWriter("tempfile/test24_bufcopy.txt"));
        
        //循环读写一行数据。
        String line = null;
        while((line=bufr.readLine())!=null){
            bufw.write(line);
            bufw.newLine();
            bufw.flush();
        }
        
        bufw.close();
        bufr.close();   
    }
}

字符流缓冲区的原理图解

字符流缓冲区的原理

字符流缓冲区read()方法和readLine()方法的实现

import java.io.IOException;
import java.io.Reader;

/**
 * 自定义一个字符流缓冲区。 用于缓冲字符数据,从而提高操作效率。 
 * 并提供了更多操作缓冲区数据的方法。 需要使用具体的流对象来完成数据的获取。
 * 
 * 分析: 缓冲区应该具备什么? 1,必须要有数组。 2,需要对数组进行操作,对数组操作一定要有角标。
 * 
 * @author Teaching
 * 
 */
public class MyBufferedReader {

    private Reader r;

    // 定义一个字符数组,作为缓冲区。
    private char[] buf = new char[1024];
    // 定义了一个索引,用于操作数组中的元素。
    private int index = 0;
    // 定义了一个变量,用于记录读取字符的个数。
    private int count = 0;

    // 需要一初始化就具备一个流对象。
    public MyBufferedReader(Reader r) {// 可以对Reader的所有子类进行高效读取。
        this.r = r;
    }

    /**
     * 提供一个可以从缓冲区中读取一个字符的方法。
     * 高效方法。
     * @throws IOException 
     * 
     */
    public int read() throws IOException {

        /*
         * 1,需要先通过流对象从底层设备上获取一定数据的数据到缓冲区数组中。 使用流对象read(char[]);
         */
        //如果count记录字符个数的变量为0,说明缓冲区已经没有字符数据。
        if(count==0){
            //需要从设备上获取一定数量的数据存储到缓冲区中,并用count记录存储字符的个数。
            count = r.read(buf);
            //每取一次新的数据,就需要将角标归0.
            index = 0;
        }
        //如果count小于0,说明到-1,没有数据了,程序直接返回-1.
        if(count<0){
            return -1;
        }
        //从缓冲区中取出一个字符。
        char ch = buf[index];
        //角标自增。
        index ++;
        //计数器要自减。
        count --;
        
        return ch;
    }
    
    /**
     *  基于高效的read方法,建立一个一次可以读取一行的数据的方法。
     *  将行终止符前的数据转成字符串返回。
     * @return
     * @throws IOException 
     */
    public String readLine() throws IOException{
        
        /*
         * 思路;
         * 
         * 从缓冲区中一次获取一个字符,并将这个字符存储到临时容器中。
         * 每获取一个字符都要进行判断,只要不是行终止符都进行存储。
         * 一旦读取到行终止符,就将临时容器中的数据转成字符串返回。
         * 
         */
        //1,定义一个临时容器。
        StringBuilder sb = new StringBuilder();
        
        //2,调用本类中的read方法,从缓冲区中读取一个字符,存储到临时容器中。
        //存的时候要注意:必须判断,如果是行终止符就不要存储了。就将临时容器中的
        //字符转成字符串返回。
        
        int ch = 0;
        while((ch=this.read())!=-1){
            if(ch=='\r'){
                continue;
            }
            
            if(ch=='\n'){
                return sb.toString();
            }
            
            sb.append((char)ch);//将读取到的字符数字转成char类型,存储到sb中。
            
        }
        
        //万一文本中最后以后没有行终止符,判断一下sb中是否有内容,如果有则返回。
        if(sb.length()!=0){
            return sb.toString();
        }
        
        
        return null;
        
    }
    

    // 关闭流资源。
    public void close() throws IOException {
        // 其实内部就是关闭具体的流。
        r.close();
    }

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容