java笔记--IO流(字符流和字节流)

IO流:

用来处理设备之间的数据传书。Java对数据的操作是通过流的方式。Java用于操作流的对象都在IO包中。流按操作数据分为两种:字节流和字符流。流按流向分为:输出流和输入流。

字符流的由来:

字节流读取文字字节数据后,不直接操作而是先查指定的编码表。获取对应的文字。在对这个文字进行操作。即:字节流+编码表。

字节流的两个顶层父类:InputStream,OutputStream
字符流的两个顶层父类:Reader,Writer

这些体系的子类都以父类名作为后缀。而且子类的前缀就是该对象的功能。

如果要操作文字数据,建议优先考虑字符流。而且要将数据从内存写到硬盘上,要使用字符流中的输出流--FileWriter。硬盘的数据基本体现是文件。若是读取则使用--FileReader。
FileWriterDemo:

//需求:将一些文字存储到硬盘一个文件中。

public class FileWriterDemo {
    
    private static final String LINE_SEPARATOR=System.getProperty("line.separator");

    public static void main(String[] args) throws IOException {
        // 创建一个可以往文件中写入字符数据的字符输出流对象。
        /*
        既然是往一个文件中写入文字数据,那么在创建对象时,就必须明确该文件(用于存储数据的目的地)。
        
        如果文件不存在,则会自动创建。
        如果文件存在,则会被覆盖。
        
        如果构造函数中加入true,可以实现对文件进行续写!
        */
        FileWriter fw=new FileWriter("demo.txt",true);
        
        /*
        调用Writer对象中的write(string)方法,写入数据。
        
        其实数据写入到临时存储缓冲区中。
        */
        fw.write("ABC"+LINE_SEPARATOR+"hahaha");
//      fw.write("xixi");
        
        /*
        进行刷新,将数据直接写到目的地中。
        */
        
//      fw.flush();
        
//      关闭流,关闭资源。在关闭前会先调用flush刷新缓冲中的数据到目的地。
//      fw.close();
        
//      fw.write("heha");// java.io.IOException: Stream closed
    }
}

运行:

IO异常的简单处理:

//line.separator换行,适用于Linux和Windows等操作系统
public class IOExceptionDemo {
    
    private static final String LINE_SEPARATOR = System.getProperty("line.separator");

    public static void main(String[] args) {
        
        FileWriter fw=null;
        try{
            fw=new FileWriter("demo.txt");
            
            fw.write("abcd"+LINE_SEPARATOR+"haha");
        }catch(IOException e){
            System.out.println(e.toString());
        }finally{
            if(fw !=null)
                try{
                    fw.close();
                }catch(IOException e){
                    throw new RuntimeException("关闭失败");
                }
        }
    }
}

FileReaderDemo:

//需求:读取一个文本文件。将读取到的字符打印到控制台。
public class FileReaderDemo {
    public static void main(String[] args) throws IOException {
        
        //  1.创建读取字符数据的流对象。
        /*
        在创建读取流对象时,必须要明确被读取的文件。一定要确定该文件是存在的。
        
        用一个读取流关联一个已存在文件
        */
        FileReader fr=new FileReader("demo.txt");
        
        int ch=0;
        
        while((ch=fr.read())!=-1){
            System.out.println((char)ch);
        }
        /*
        用Reader中的read方法读取字符。
        int ch=fr.read();
        System.out.println((char)ch);
        int ch1=fr.read();
        System.out.println(ch1);
        int ch2=fr.read();
        System.out.println(ch2);
        */
        fr.close();
    }
}

运行:

FileReaderDemo2:

public static void main(String[] args) throws IOException {
        
        FileReader fr=new FileReader("demo.txt");
        /*
        使用read(char[])读取文本文件数据
        
        先创建字符数组
        */
        char[] buf=new char[1024];
        
        int len=0;
        
        while((len=fr.read(buf))!=-1){
            System.out.println(new String(buf,0,len));
        }
        /*
        int num = fr.read(buf);//将读取到的字符存储到数组中。
        System.out.println(num+":"+new String(buf,0,num));
        int num1 = fr.read(buf);//将读取到的字符存储到数组中。
        System.out.println(num1+":"+new String(buf,0,num1));
        int num2 = fr.read(buf);//将读取到的字符存储到数组中。
        System.out.println(num2+":"+new String(buf));
        */
        
        fr.close();
    }

运行:
字符流:Writer,Reader

FileReader
FileWriter
BufferedReader
BufferedWriter

将一些文字存储到硬盘一个文件中。
操作文字数据-->字符流(优先考虑)
从内存写到硬盘-->字符流中的输出流(Writer)
硬盘数据基本体现是文件-->FileWriter。

public class CopyTextTest {
    public static void main(String[] args) throws IOException { 
        //1.读取一个已有的文本文件,使用字符读取流和文件相关联。
        FileReader fr=new FileReader("IO流_2.txt");
        //2.创建一个目的,用于存储读到的数据。
        FileWriter fw=new FileWriter("copytext_1.txt");
        //3.频繁的读写操作。
        int ch=0;
        while((ch=fr.read())!=-1){
            fw.write(ch);
        }
        //关闭流资源。
        fw.close();
        fr.close();
    }
}

运行:

创建字符数组存储读取到的数据--缓冲区。

public class CopyTextTest2 {
    
    private static final int BUFFER_SIZE = 1024;

    public static void main(String[] args) {
        
        FileReader fr=null;
        FileWriter fw=null;
        try{
            fr=new FileReader("IO流_2.txt");
            fw=new FileWriter("copytext_2.txt");
            
            //创建一个临时容器,用于缓存读取到的字符
            char[] buf=new char[BUFFER_SIZE];//这是缓冲区。
            
            //定义一个变量记录读取到的字符数,(其实就是往数组里装的字符个数)
            int len=0;
            
            while((len=fr.read(buf))!=-1){
                fw.write(buf,0,len);
            }
        }catch(Exception e){
//          System.out.println("读写失败");
            throw new RuntimeException("读写失败");
        }finally{
            if(fw!=null)
                try{
                    fw.close();
                }catch(IOException e){
                    e.printStackTrace();
                }
            if(fr!=null)
                try{
                    fr.close();
                }catch(IOException e){
                    e.printStackTrace();
                }
        }
    }
}

为了提高写入的效率。使用字符流的缓冲区。

public class BufferWriterDemo {

    private static final String LINE_SEPARATOR=System.getProperty("line.separator");
    
    public static void main(String[] args) throws IOException {
        
        FileWriter fw=new FileWriter("buf.txt");
        
        //为了提高写入的效率。使用了字符流的缓冲区。
        //创建了一个字符写入流的缓冲区对象,并和指定要被缓冲的流对象相关联
        BufferedWriter bufw=new BufferedWriter(fw);

        //使用缓冲区的写入方法将数据先写入到缓冲区中。
        /*bufw.write("abcdfa"+LINE_SEPARATOR+"HAHA");
        bufw.write("xixixi");
        bufw.newLine();
        bufw.write("hehe");*/
        
        for(int x=1;x<=4;x++){
            bufw.write("abcdgf"+x);
            bufw.newLine();
            bufw.flush();
        }   
        //使用缓冲区的刷新方法将数据输入到目的地中。
//      bufw.flush();
        
        //关闭缓冲区。其实关闭的就是被缓冲的流对象。
        bufw.close();
        
        /*fw.write("hehe");
        fw.close();*/
    }
}

运行:

读:

public class BufferReaderDemo {

    public static void main(String[] args) throws IOException {
        
        FileReader fr=new FileReader("buf.txt");
        
        BufferedReader bufr=new BufferedReader(fr);
        
        String line=null;
        
        while((line=bufr.readLine())!=null){
            System.out.println(line);
        }
        /*
        String line1=bufr.readLine();
        System.out.println(line1);
        String line2=bufr.readLine();
        System.out.println(line2);
        String line3=bufr.readLine();
        System.out.println(line3);
        String line4=bufr.readLine();
        System.out.println(line4);
        String line5=bufr.readLine();
        System.out.println(line5);
        */
        bufr.close();
        
    }

        
    /**
     * @throws FileNotFoundException
     * @throws IOException
     */
    
    public static void demo() throws FileNotFoundException, IOException {
        FileReader fr=new FileReader("buf.txt");
        
        char[] buf=new char[1024];
        
        int len=0;
        while((len=fr.read(buf))!=-1){
            System.out.println(new String(buf,0,len));
        }
        
    }
}

运行:

CopyTextByBufTest:

public static void main(String[] args) throws IOException {
        
        FileReader fr=new FileReader("buf.txt");
        BufferedReader bufr=new BufferedReader(fr);
        
        FileWriter fw=new FileWriter("buf_copy.txt");
        BufferedWriter bufw=new BufferedWriter(fw);
        
        
        String line=null;
        while((line=bufr.readLine())!=null){
            bufw.write(line);
            bufw.newLine();
            bufw.flush();
        }
        /*
        int ch=0;
        
        while((ch=bufr.read())!=-1){
            
            bufw.write(ch);
        }
        */
        bufw.close();
        bufr.close();
    }

运行:

自定义缓冲区原理:
缓冲区其实就是封装了一个数组,并对外提供了更多的访问数组的方法。而这些方法最终操作的都是数组的角标。
分析:从源中获取一批数据装进缓冲区中,再从缓冲区中不断取出一个一个数据。取完后,再从数据源中继续取出一批数据进缓冲区。取完时,用-1结束标记。

public class MyBufferedReader extends Reader{

    private Reader r;
    
    //定义一个数组作为缓冲区
    private char[] buf=new char[1024];
    
    //定义一个指针用于操作这个数组中的元素。当操作到最后一个元素后,指针应该归零
    private int pos=0;
    
    //定义一个计数器用于记录缓冲区的数据个数。当该数据减到0,就从源中继续获取数据到缓冲区中
    private int count=0;
    
    MyBufferedReader(Reader r){
        this.r=r;
    }
    
//  该方法从缓冲区中一次取一个字符
    public int myRead() throws IOException{
        
        if(count==0){
            count=r.read(buf);
            pos=0;
        }if(count<0)
            return -1;
        
        char ch=buf[pos++];
        
        count--;
        
        return ch;
        /*
        //1.从源中获取一批数据到缓冲区中。需要先做判断,只有计数器为0时,才需要从源中获取数据。
        if(count==0){
            count=r.read(buf);
            
            if(count<0)
                return -1;
            
        //每次获取数据到缓冲区后,角标归零
            pos=0;
            char ch=buf[pos];
            
            pos++;
            count--;
            
            return ch;
        }else if(count>0){
            
            char ch=buf[pos];
            
            pos++;
            count--;
            
            return ch;
        }*/
    }
    
    public String myReadLine() throws IOException{
        
        StringBuilder sb=new StringBuilder();
        
        int ch=0;
        while((ch=myRead())!=-1){
            
            if(ch=='\r')
                continue;
            if(ch=='\n')
                return sb.toString();
            
            //将从缓冲区中读到的字符,存储到缓存行数据的缓冲区中。
            sb.append((char)ch);
        }
        if(sb.length()!=0)
            return sb.toString();
        return null;
        
    }
    public void myColse() throws IOException{
        r.close();
    }


    @Override
    public void close() throws IOException {
        
    }

    @Override
    public int read(char[] cbuf, int off, int len) throws IOException {
        
        return 0;
    }
}
public class MyBufferedReaderDemo {

    public static void main(String[] args) throws IOException {
        
        FileReader fr=new FileReader("buf.txt");
        
        MyBufferedReader bufr=new MyBufferedReader(fr);
        
        String line=null;
        
        while((line=bufr.myReadLine())!=null){
            System.out.println(line);
        }
        
        bufr.myColse();
        
        /*Collections.reverseOrder();
        HashMap map=null;
        map.values();*/
    }

}

运行:
装饰设计模式:对一组对象的功能进行增强时,就可以使用该模式进行问题的解决。
装饰和继承都能实现一样的特点:进行功能的扩展增强。

首先有一个集成体系。

Writer
    |--TextWriter:用于操作文本
    |--MediaWriter:用于操作媒体

想要对操作的动作进行效率的提高。
按照面向对象,可以通过继承对具体的进行功能的扩展。
效率提高需要缓冲技术。

Writer(继承体系)
    |--TextWriter:用于操作文本
        |--BufferTextWriter:加入缓冲技术操作文本对象
    |--MediaWriter:用于操作媒体
        BufferMediaWriter:

这个体系进行功能扩展,有了流对象。这时需要提高效率所以产生子类。就会发现只为提高功能进行的继承,导致继承
体系越来越臃肿。不够灵活。

装饰:
将缓冲进行单独的封装,哪个对象需要缓冲就将哪个对象和缓冲关联。

class Buffer{
    Buffer(TextWriter w)
    {}
    
    Buffer(MediaWirter w)
    {
    
    }
}
class BufferWriter extends Writer{
    BufferWriter(Writer w)
    {
    }
}
Writer
    |--TextWriter:用于操作文本
    |--MediaWriter:用于操作媒体
    |--BufferWriter:用于提高效率

装饰比继承灵活

特点:装饰类和被装饰类都必须所属同一个接口或者父类.

public class PersonDemo {

    public static void main(String[] args) {
        
        Person p=new Person();
//      p.chifan();
        
        NewPerson p1=new NewPerson(p);
        p1.chifan();
        
        NewPerson2 p2=new NewPerson2();
        p2.chifan();
    }
}

class Person{
    void chifan(){
        System.out.println("chifan");
    }
}

//这个类的出现是为了增强Person而出现的
class NewPerson{
    private Person p;
    NewPerson(Person p){
        this.p=p;
    }
    public void chifan(){
        System.out.println("开胃酒");
        p.chifan();
        System.out.println("甜点");
    }
}

class NewPerson2 extends Person{
    public void chifan(){
        System.out.println("开胃酒");
        super.chifan();
        System.out.println("甜点");
    }
}

LineNumberReader(加行号):

public class LineNumberReaderDemo {

    public static void main(String[] args) throws IOException {
        
        FileReader fr=new FileReader("IO流_2.txt");
        LineNumberReader lnr=new LineNumberReader(fr);
        
        String line=null;
        lnr.setLineNumber(100);
        while((line=lnr.readLine())!=null){
            System.out.println(lnr.getLineNumber()+":"+line);
        }
        lnr.close();
    }
}

运行:
字节流:InputStream,OutoutStream

FileInputStream
FileOutputStream
BufferedInputStream
BufferedOutputStream

public class ByteStreamDemo {

    public static void main(String[] args) throws IOException {
        
        demo_write();
        demo_read();

    }

    private static void demo_write() throws IOException {
        
//      1.创建字节输出流对象。用于操作文件。
        FileOutputStream fos=new FileOutputStream("bytedemo.txt");
        
//      2.写数据。直接写入到了目的地中。
        fos.write("abcdfg".getBytes());
        
//      fos.flush();
        fos.close();//关闭资源动作要完成
    } 

    private static void demo_read() throws IOException {
        
//      1.创建一个读取流对象。和指定文件关联。
        FileInputStream fis=new FileInputStream("bytedemo.txt");
        /*
        System.out.println(fis.available());
        byte[] buf=new byte[fis.available()];
        fis.read(buf);
        System.out.println(new String(buf));
        
//      建议使用这种读取数据的方式
        byte[] buf=new byte[1024];
        int len=0;
        
        while((len=fis.read(buf))!=-1){
            System.out.println(new String(buf,0,len));
            
            int ch=0;
            while((ch=fis.read())!=-1){
                System.out.println((char)ch);
            }
            
//          一次读取一个字节
            int ch=fis.read();
            System.out.println(ch);*/
            
            fis.close();
        }       
}

运行:

CopyMp3Test:

public class CopyMp3Test {

    public static void main(String[] args) throws IOException {
        
        copy_1();
        copy_2();
        copy_3();
        copy_4();

    }
    //千万不要用,没有效率
    private static void copy_4() throws IOException {
        
        FileInputStream fis=new FileInputStream("c:\\0.mp3");
        FileOutputStream fos=new FileOutputStream("c:\\4.mp3");
        
        int ch=0;
        
        while((ch=fis.read())!=-1){
            fos.write(ch);
        }
        fos.close();
        fis.close();
    }
    //不建议
    private static void copy_3() throws IOException {
        
        FileInputStream fis=new FileInputStream("c:\\0.mp3");
        FileOutputStream fos=new FileOutputStream("c:\\3.mp3");
        
        byte[] buf=new byte[fis.available()];
        fis.read(buf);
        fos.write(buf);
        fos.close();
        fis.close();
        
    }

    private static void copy_2() throws IOException {
        
        FileInputStream fis=new FileInputStream("c:\\0.mp3"); 
        BufferedInputStream bufis=new BufferedInputStream(fis);
        
        FileOutputStream fos=new FileOutputStream("c:\\2.mp3");
        BufferedOutputStream bufos=new BufferedOutputStream(fos);
        
        int ch=0;
        
        while((ch=bufis.read())!=-1){
            bufos.write(ch);
        }
        bufos.close();
        bufis.close();
        
    }

    private static void copy_1() throws IOException {
        
        FileInputStream fis=new FileInputStream("c:\\0.mp3");
        FileOutputStream fos=new FileOutputStream("c:\\1.mp3");
        
        byte[] buf=new byte[1024];
        
        int len=0;
        while((len=fis.read(buf))!=-1){
            fos.write(buf,0,len);
        }
        
        fos.close();
        fis.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

推荐阅读更多精彩内容

  • 概述 java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。java.io ...
    Steven1997阅读 9,178评论 1 25
  • IO概览 字节流与字符流的区别字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用...
    Sophie12138阅读 725评论 0 0
  • 概述: 1、IO流:即Input Output的缩写。 2、特点:1)IO流用来处理设备间的数据传输。2)Java...
    玉圣阅读 1,238评论 0 3
  • 妈妈,你愿意听我说吗 早上起床,咪咪一脸的不开心,然后就 出现:衣服没穿合适,袜子也有问题,我知 道她有情绪...
    刘慧烨阅读 426评论 0 1
  • 这个故事是豆子第一位阿姨给我讲的。 我们那个村子曾经有两个厂子,A厂和B厂,都是做餐桌的转盘。我在A厂工作,大家都...
    近馨阅读 291评论 1 4