java入门(缓冲流、序列化流、转换流、打印流)

2020年10月31日 8点热度 0条评论 来源: Li_CSDN_Li

缓冲流、序列化流、转换流、打印流

缓冲流

字节缓冲流也称高效流,其实就是对基本流的一个增强,内部用了一个默认大小(1024*8)的缓冲区就是字节数组用于读写数据,从而减少IO次数,提高效率

缓冲流的用法和我们基本流的用法是一样

  • 字节输入缓冲流:BufferedInputStream

    public BufferedInputStream(InputStream in)
    
  • 字节输出缓冲流:BufferedOutputStream

    public BufferedOutputStream(OutputStream out)
    

【练习】拷贝一个文件对比下普通流和高效流的效率。

/* 使用普通流和高效流分别进行文件的拷贝 */
public class Demo01 { 
    public static void main(String[] args) { 
        copy1(); //62108 自己定义字节数组 38
        //copy2(); // 209

    }

    /* 基本流 */
    public static void copy1() { 
        System.out.println("开始拷贝.....");
        long t1 = System.currentTimeMillis();
        //将music1/Rolling.mp3 拷贝到 music2/Rolling1.mp3
        //1.创
        try (FileInputStream fis = new FileInputStream("music1/Rolling.mp3");
             FileOutputStream fos = new FileOutputStream("music2/Rolling1.mp3")) { 
            //2.读,写
            //读一个字节,写一个字节
            //int b;
            //while ((b = fis.read()) != -1) { 
            // fos.write(b);
            //}
            byte[] bytes = new byte[8 * 1024];
            int len;
            while ((len = fis.read(bytes)) != -1) { 
                fos.write(bytes, 0, len);
            }


            //3.关:自动关
        } catch (IOException e) { 
            e.printStackTrace();
        }
        long t2 = System.currentTimeMillis();
        System.out.println("花费时间 = " + (t2 - t1));

    }

    /* 高效流 */
    public static void copy2() { 
        System.out.println("开始拷贝.....");
        long t1 = System.currentTimeMillis();
        //将music1/Rolling.mp3 拷贝到 music2/Rolling2.mp3
        //FileInputStream : BufferedInputStream
        //FileOutputStream: BufferedOutputStream

        //1.创
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("music1/Rolling.mp3"));
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("music2/Rolling2.mp3"))
        ) { 
            //2.读,写
           int b;
           while ((b = bis.read()) != -1) { 
               //读一个字节,写一个字节
               bos.write(b);
           }




            //3.关
        } catch (IOException e) { 
            e.printStackTrace();
        }

        long t2 = System.currentTimeMillis();
        System.out.println("花费时间 = " + (t2 - t1));
    }
}

字符缓冲流

字符缓冲流用法和普通的字符流一样,但他们各自都有一个特有方法:

  • BufferedReader

    public BufferedReader(Reader in) :创建一个 新的缓冲输入流。
    例如:
    BufferedReader br = new BufferedReader(new FileReader("br.txt"));
    

    特有读行方法

    public String readLine(): 一次读一行,读到最后没了,返回null
    
  • BufferedWriter

    public BufferedWriter(Writer out): 创建一个新的缓冲输出流。
    例如:
    BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
    

    特有的换行功能

    public void newLine(): 换行
    

    【练习】

    使用高效流写《静夜思》数据到文件中,要求每句诗要换行。再使用高效流按行读取数据

    /* */
    public class Demo01 { 
        public static void main(String[] args) { 
            //write();
            read();
    
        }
    
        /* BufferedWriter */
        public static void write() { 
            //使用高效流写《静夜思》数据到文件中,要求每句诗要换行。
            //BufferedWriter: FileWriter
    
            //1.创
            try (BufferedWriter bw = new BufferedWriter(new FileWriter("file01.txt"))) { 
                //2.写
    
                bw.write("《静夜思》");
                //换行特有方法:public void newLine()
                bw.newLine();
                bw.write("李白");
                bw.newLine();
                bw.write("床前明月光");
                bw.newLine();
                bw.write("疑是地上霜");
                bw.newLine();
                bw.write("举头望明月");
                bw.newLine();
                bw.write("低头思故乡");
                bw.newLine();
    
                //3.关:自动关
            } catch (IOException e) { 
                e.printStackTrace();
            }
    
    
        }
    
        /* BufferedReader */
        public static void read() { 
            //再使用高效流按行读取数据
            //BufferedReader: FileReader
    
            //1.创
            try (BufferedReader br = new BufferedReader(new FileReader("file01.txt"));) { 
                //2.读
    
                String line;
                while ((line = br.readLine()) != null) { 
                    System.out.println("line = " + line);
                }
    
                //3.关:自动关
            } catch (IOException e) { 
                e.printStackTrace();
            }
    
    
        }
    
    }
    

出师表练习

将《出师表》内容排序

3.侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必得裨补阙漏,有所广益。
8.愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言,深追先帝遗诏,臣不胜受恩感激。
4.将军向宠,性行淑均,晓畅军事,试用之于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。
2.宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
1.先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。
9.今当远离,临表涕零,不知所言。
6.臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
7.先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐付托不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。
5.亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。

【思路分析】

  1. 先将9段读取到一个集合中保存

    可以通过BufferedReader按行读取

  2. 把集合中内容按照段落序号升序排序

    Collectionssort方法

  3. 把排序好的集合字符串内容遍历写到新文件

    可以通过BufferedWriter换行

【代码实现】

/* 将出师表中的段落进行排序 思路: 1.先定义一个字符串集合容器进行存储读取的段落。 2.开始进行使用字符高效读取流进行读行,存储到集合中 3.排序 4.按照顺序把每一个段落写出去 */
public class Demo01 { 
    public static void main(String[] args) { 
        //1.先定义一个字符串集合容器进行存储读取的段落。
        ArrayList<String> list = new ArrayList<>();
        try (BufferedReader br = new BufferedReader(new FileReader("file_OutTeacherTable.txt"));) { 
            //2.开始进行使用字符高效读取流进行读行,存储到集合中
            String line;
            while ((line = br.readLine()) != null) { 
                list.add(line);
            }
        } catch (IOException e) { 
            e.printStackTrace();
        }
        //3.排序
        //自己定义比较器进行比较
        Collections.sort(list, new Comparator<String>() { 
            @Override
            public int compare(String o1, String o2) { 
                int num1 = Integer.parseInt(o1.split("\\.")[0]);
                int num2 = Integer.parseInt(o2.split("\\.")[0]);
                return num1-num2;
            }
        });//排序
        //for (String e : list) { 
        // System.out.println("e = " + e);
        //}
        //4.按照顺序把每一个段落写出去
            //1.创
        try (BufferedWriter bw = new BufferedWriter(new FileWriter("file02.txt"));) { 
            //2.写
            for (String line : list) { 
                bw.write(line);
                bw.newLine();//换行
            }

            //3.自动关
        } catch (IOException e) { 
            e.printStackTrace();
        }
    }
}

字符集和字符编码

字符集

字符(Character)是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。字符集(Characterset)是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等。

计算机要准确的处理各种字符集文字,就需要进行字符编码,以便计算机能够识别和存储各种文字。

字符编码

字符编码就是将字符集中的字符进行编号用一个数字进行对应。 存储该字符是存储的就是这个数字了。

编码:按照字符编码的规则,将字符对应的数字转化为二进制数据存储到计算机

解码:按照字符编码的规则,将计算机中读取的二进制数据转化为数字从而获取与之对应的字符

计算机中处理字符数据一定要注意,编码和解码的规则需要同一个,否则会出现乱码的情况。

乱码问题实践

编码和解码都要参照字符编码表,如果采用的参照不一样,导致乱码

【练习】

IDEA默认使用的编码规则为:UTF-8,Windows系统中,默认采用的编码规则为:GBK

在IDEA软件之外计算机中创建一个文本文件输入中文,然后拷贝到IDEA项目中进行读取数据,并输出到控制台,观察现象。

【代码实现】

fileGBK.txt里的内容为:    静夜思
public class Demo01 { 
    public static void main(String[] args) throws IOException { 
        //默认采用的编码方案是UTF-8
        FileReader fr = new FileReader("fileGBK.txt");

        System.out.println((char) fr.read());// �
        System.out.println((char) fr.read());// �
        System.out.println((char) fr.read());// ҹ

        fr.close();

    }
}

如何解决乱码的问题?如果不想乱码,编解码采用的编码规则要一致。

已知一个文件编码为GBK,如何在代码中指定GBK编码读取文件?

需要使用到转换流

InputStreamReader的使用

InputStreamReader.是字节流到字符流的桥梁,可以指定字符编码进行读取数据。我们之前学习的FileReader就是InputStreamReader的子类。将读取的字节按照默认编码【UTF-8】转化为字符。

所以在方法的使用上,跟之前的FileReader的使用是一致的。步骤如下:

  1. InputStreamReader(InputStream in): 创建一个使用默认字符集的字符流。 【UTF-8InputStreamReader(InputStream in, String charsetName): 创建一个指定字符集的字符流。
    

    参数 charsetName 就是字符编码表的名称: GBKGB2312GB18030UTF-8ASCII , ISO-8859-1

  2. int read()读取单个字符返回,如果读取完毕返回-1
    int read(char[] cbuf) 将字符读入数组,返回读取的有效个数,如果没有读取有效字符返回-1
  3. void colse()
    

【练习】将GBK文件的文本读取打印到控制台中

/* 将GBK文件的文本读取打印到控制台中 */
public class Demo01 { 
    public static void main(String[] args) { 
        //1.创
        try (//InputStreamReader isr = new InputStreamReader(new FileInputStream("fileGBK.txt"));//默认采用UTF-8
             InputStreamReader isr = new InputStreamReader(new FileInputStream("fileGBK.txt"), "gbk");//指定GBK
        ) { 
            //2.读
            char[] chars = new char[10];
            int len;
            while ((len = isr.read(chars)) != -1) { 
                System.out.println(new String(chars, 0, len));
            }

            //3.关

        } catch (IOException e) { 
            e.printStackTrace();
        }

    }
}

OutputStreamWriter

转换流java.io.OutputStreamWriter ,是Writer的子类,是从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。

简单的说就是可以按照指定编码写出数据到文件

FileWriterOutputStreamWriter的子类,基本用法与FileWriter一致

  1. OutputStreamWriter(OutputStream in): 创建一个使用默认字符集的字符流。 
    OutputStreamWriter(OutputStream in, String charsetName): 创建一个指定字符集的字符流。
    
    

    参数 charsetName 就是字符编码表的名称: GBKGB2312GB18030UTF-8ASCII , ISO-8859-1

  2. void flush() 刷新该流的缓冲。 
    void write(char[] cbuf) 写入字符数组。 
    void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。 
    void write(int c) 写入单个字符。 
    void write(String str) 写入字符串。 
    void write(String str, int off, int len) 写入字符串的某一部分。 
    
    
  3. void close() 关闭此流,但要先刷新它。 
    

【练习】指定GBK编码写出字符到一个文件中。

public class Demo01 { 
    public static void main(String[] args) { 
        //指定GBK编码写出字符到一个文件中。

        //1.创
        try (
                //OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("fileGBK2.txt"));//默认编码:UTF-8
                OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("fileGBK2.txt"), "GBK");//指定编码:GBK
        ) { 
            //2.写

            osw.write("床前明月光");
            //3.关:自动关

        } catch (IOException e) { 
            e.printStackTrace();
        }
    }
}

转换流使用的原理分析

练习: 将GBK文件转化为UTF-8文件

【步骤分析】

  1. 创建转化输入和输出流对象
  2. 指定GBK编码的转换流,读取文本文件。
  3. 使用UTF-8编码的转换流,写出文本文件。
  4. 关流

【代码实现】

public class Demo01 { 
    public static void main(String[] args) { 
        //将GBK文件 fileGBK2.txt 转化为UTF-8文件 fileUtf-8.txt

        //1.创
        try (InputStreamReader isr = new InputStreamReader(new FileInputStream("fileGBK2.txt"), "GBK");
             OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("fileUTF-8.txt"), "UTF-8")) { 
            //2.读,写
            int c;
            while ((c = isr.read()) != -1) {  //以GBK读取
                osw.write(c);//以UTF-8写
            }

            //3.关

        } catch (IOException e) { 
            e.printStackTrace();
        }

    }
}

对象的序列化

  1. 对象的序列化: 将堆内存中对象的字节数据,保存到磁盘文件中去 【持久化】需要使用一个类==ObjectOutputStream==

  2. 如果要使对象能够序列化,要求这个对象的类型满足2个条件:
    1)这个类型必须要实现一个接口erializable, 目的就是为标记这个类型是可以被序列化的。如果没有实现,会报错:otSerializableException

  3. 2)如果含有引用类型属性,这个属性类型必须也实现了Serializable,如果某个属性不需要被序列化,要使用关键字transient【短暂的,瞬态】修饰

    public class Student implements Serializable { 
        private transient int age; //不会序列化
        private String name;
        private String className;
    
        //...构造方法
        //...getter/setter
        //...toString
    }
    
    

当一个对象需要序列化时,操作步骤如下:

  1. public ObjectOutputStream(OutputStream out)
    创建写入指定 OutputStream 的 ObjectOutputStream。
    
  2. void writeObject(Object obj)
    
  3. void close()
    

【练习】

创建学生类及其对象,将对象序列化到文件中

学生类:

public class Student implements Serializable { 
    private transient int age; //age将不会序列化到文件中
    private String name;
    private String classname;

    public Student() { 
    }

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

  //getter/settter
  //toString
}

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Demo01 { 
    public static void main(String[] args) { 
        //创建对象
        Student stu = new Student(18, "迪丽热巴", "黑马86期");
        //将stu对象,序列化到一个文件中。【将对象数据保存到硬盘文件】

        //借助ObjectOutputStream
        //1.创
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("fileObj.obj"));) { 
            //2.写
            oos.writeObject(stu);

            //3.关:自动关
        } catch (IOException e) { 
            e.printStackTrace();
        }

    }
}

对象的反序列化操作

对象的反序列化即将本地文件中的字节信息读取到内存转化为对象。

==ObjectInputStream==反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象

反序列化使用的类为bjectInputStream,就是一个字节输入流,使用步骤跟之前的输入流是一样的。

使用步骤:

  1. public ObjectInputStream(InputStream in): 
    创建一个指定InputStream的ObjectInputStream。
    
  2. Object readObject () : 读取一个对象。
    
  3. void close():关流	
    

【基本使用】

public class Demo01 { 
    public static void main(String[] args) { 
        //将fileObj.obj中的对象信息,读取到内存中形成一个对象

        //借助ObjectInputStream 是一个输入流
        //1.创
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("fileObj.obj"))) { 
            //2.读
            Object o = ois.readObject(); //1
            System.out.println("o = " + o);
            //如果读取最后没有对象读取,不是返回null,不是返回-1,直接报错。
            o = ois.readObject();//2 EOFException End Of File
            System.out.println("o = " + o);


            //3.关

        } catch (IOException e) { 
            e.printStackTrace();
        } catch (ClassNotFoundException e) { 
            e.printStackTrace();
        }


    }
}

如果读取最后没有对象读取,不是返回null,不是返回-1,直接报错。

使用注意:

  1. 如果不能找到class文件,报ClassNotFoundException

  2. JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException异常。

    需要保证类型的版本号序列化和反序列化时的版本号要一致,可以自己在类型上定义一个常量表示版本,如下:

    public final static long serialVersionUID =1L; 
    

练习:集合对象的序列和反序列化操作

【需求】

  1. 将存有多个自定义对象的集合序列化操作,保存到list.txt文件中。
  2. 反序列化list.txt ,并遍历集合,打印对象信息。

【步骤分析】

序列化

  1. 把若干学生对象 ,保存到集合中。
  2. 把集合序列化。

反序列化

  1. 反序列化读取时,只需要读取一次,转换为集合类型。
  2. 遍历集合,可以打印所有的学生信息

【代码实现】

/* 1. 将存有多个自定义对象的集合序列化操作,保存到list.txt文件中。 2. 反序列化list.txt ,并遍历集合,打印对象信息。 */
public class Demo01 { 
    public static void main(String[] args) { 
        //writeObj();
        readObj();

    }

    //1. 将存有多个自定义对象的集合序列化操作,保存到list.txt文件中。
    public static void writeObj() { 
        ArrayList<Student> list = new ArrayList<>();
        list.add(new Student(18, "迪丽热巴1", "黑马86"));
        list.add(new Student(19, "迪丽热巴2", "黑马86"));
        list.add(new Student(20, "迪丽热巴3", "黑马86"));

        //把集合对象list保存到文件中【序列化】

        //1.创
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("list.txt"))) { 
            //2.写
            oos.writeObject(list);
            //3.关:自动关
        } catch (IOException e) { 
            e.printStackTrace();
        }


    }

    //2. 反序列化list.txt ,并遍历集合,打印对象信息。
    public static void readObj() { 
        //1.创
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("list.txt"))) { 
            //2.读
            ArrayList<Student> o = (ArrayList<Student>) ois.readObject();
            for (Student student : o) { 

                System.out.println("student = " + student);
            }
            //3.关
        } catch (IOException e) { 
            e.printStackTrace();
        } catch (ClassNotFoundException e) { 
            e.printStackTrace();
        }

    }


}

打印流

平时我们在控制台打印输出,是调用print方法和println方法完成的,这两个方法都来自于java.io.PrintStream类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式。

使用步骤:

  1.  public PrintStream(String fileName) 关联一个文件,写出的内容都到这个文件中去了
    
  2. public void println(数据) : 打印数据,并换行
    public void print(数据): 打印数据不换行
    
  3. void close()
    

扩展:

System.out表示的对象就是打印流类型的对象。

可以通过改变系统输出流向:System.setOut(打印流);

【代码实践】

public class Demo01 { 
    public static void main(String[] args) { 
        //1.创
        // public PrintStream(String fileName) 关联一个文件,写出的内容都到这个文件中去了

        try (PrintStream ps = new PrintStream("file10.txt");) { 
            //2.写
            //public void println(数据) : 打印数据,并换行
            //public void print(数据): 打印数据不换行
            ps.println("Hello World!");
            ps.print("abc");
            ps.print("def");

        //3.关
        } catch (IOException e) { 
            e.printStackTrace();
        }


    }
}
public class Demo02 { 
    public static void main(String[] args) { 
        //1.创
        // public PrintStream(String fileName) 关联一个文件,写出的内容都到这个文件中去了

        try (PrintStream ps = new PrintStream("file11.txt");) { 
            //2.写
            //public void println(数据) : 打印数据,并换行
            //public void print(数据): 打印数据不换行
            System.setOut(ps);
            System.out.println("Hello World");


        //3.关
        } catch (IOException e) { 
            e.printStackTrace();
        }


    }
}
    原文作者:Li_CSDN_Li
    原文地址: https://blog.csdn.net/Li_CSDN_Li/article/details/109409704
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。