Day22 --序列流 内存输出流 随机访问流 对象操作流 数据输入输出流 打印流 标准输入输出流 Properties

 a.
    序列流  --SequenceInputStream
        概述
            * 序列流又称 整合流。序列流是将多个 字节输入流 整合成一个。从序列流中读取数据时,是从被整合的第一个流开始读,读完第一个之后,读第二个,以此类推。

        构造方法
            * SequenceInputStream(InputStream s1, InputStream s2);通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此 SequenceInputStream 读取的字节。
            * 
        目的
            * 使用序列流是 减少对多个输入流的读取。
        
        使用
//        字节输入流
        FileInputStream fis1 = new FileInputStream("文件1.txt");
        FileInputStream fis2 = new FileInputStream("文件2.txt");
        
//        使用序列流将【两个(这里只能是两个,由构造参数决定)】  字节流  整合成一个
        SequenceInputStream sis = new SequenceInputStream(fis1, fis2);
//        字节输出流
        FileOutputStream fos = new FileOutputStream("文件1_sequence_文件2.txt");
        
        int len;
        byte[] b = new byte[1024 *8];
        while(( len = sis.read(b)) !=-1){
            fos.write(b, 0, len);
        }
        
        sis.close();  // 关闭 序列流资源即可,会将构造方法中传入的输入流对象给关闭。
        fos.close();  // 关闭字节输出流

        
        序列流整合多个
            概述
                * 当有多个字节输入流需要合并一起读到一个文件中时,可用SequenceInputStream中的宁一个构造函数
            构造方法
                * SequenceInputStream(Enumeration<? extends InputStream> e);  通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。
            使用
            FileInputStream fis1 = new FileInputStream("a1.txt");
            FileInputStream fis2 = new FileInputStream("a2.txt");
            FileInputStream fis3 = new FileInputStream("a3.txt");
// 创建vector集合            
            Vector<InputStream> vector = new Vector<>();  
// 将 字节输入流 传入 Vector集合中
            vector.add(fis1); 
            vector.add(fis2);
            vector.add(fis3);
// 也可以传入构造
            vector.add(new FileInputStream("a4.txt"));  
// 也可以传入构造
            vector.add(new FileInputStream("a5.txt")); 
// 创建枚举引用
            Enumeration<InputStream> elements = vector.elements();
// 将枚举传递给SequenceInputStream构造,即将多个流整合成一个
            SequenceInputStream sis = new SequenceInputStream(elements); 
            
//  字节输出流
            FileOutputStream fos = new FileOutputStream("整合a.txt");
            int len;
            byte[] b = new byte[1204*8];
            while(( len = sis.read(b)) != -1){
                fos.write(b, 0, len);
            }
            sis.close(); //  关 序列流集合对象
            fos.close(); // 关 字节流输出对象
            


b.
    内存输出流 --ByteArrayOutputStream
        概述
            * 该输出流可以向内存中写入数据,将内存当做一个缓冲区,写出之后可以一次性获取所有数据
            * 此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长(又创建了一个新的数组来存储)。可使用 toByteArray() 和 toString() 获取数据。 
            
        注意:关闭 ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。 
    
        目的
            * 用来解决 字节输入流读取中文会出现乱码的问题
            
        字节输入流读取中文会出现乱码 问题解决?
            * 方案一:字符流读取
            * 方案二:内存输出流读取

        方法
            * toByteArray(); 使用指定码表将数据输出
            * toString(); 不使用码表将数据输出
            
        使用    
        FileInputStream fis = new FileInputStream("整合a.txt");
        ByteArrayOutputStream bao = new ByteArrayOutputStream(); //内存输出流 (在内存中创建了一个新的可以自动增长的byte数组)
        
        int b;
        while((b = fis.read()) != -1){  //将读到的数据逐个写到内存中
            bao.write(b); //使用bao,是将数据写到内存中(缓冲区中)
        }
        
//        将内存缓冲流中的数据全部获取出来,并存入数组中
        byte[] byteArray = bao.toByteArray(); //toByteArray() 用于获取 内存输出流 写入到 内存 的所有数据
//        两种获取内存中数据的方式:
        System.out.println(new String(byteArray)); //拿到 整合a.txt 一次性写到内存输出流的所有数据
        System.out.println(bao.toString()); //在打印输出语句中可以省略toString方法,因为系统会默认调用。
        
        fis.close();
//        bao.close(); 内存输出流,不用关,因为不是往硬盘中写数据的。


内存输出流之【【【黑马面试题】】】】
    案例:
        定义一个文件输入流,调用read(byte[] b)方法,将a.txt文件中的内容打印出来(byte数组大小限制为5)
    使用
//         1. 因为read(byte[] b); 是字节输入流中的方法,所以创建字节输入流
        FileInputStream fis = new FileInputStream("a2.txt");
//         3. 因为大小为5可能读出来会有乱码,所以创建 内存输出流
        ByteArrayOutputStream bao = new ByteArrayOutputStream();
        
        int len;
//         2. 创建字节数组,设置大小为5,即每次读取5个字节
        byte[] b = new byte[5];
        while( ( len = fis.read(b)) !=-1){
            bao.write(b, 0, len);
        }
//        4. 使用内存输出流将数据一次性读到内存中。
        byte[] byteArray = bao.toByteArray();
        
//         5. 将内存输出流中的数据全部转换成String进行打印
        System.out.println(new String(byteArray));
        System.out.println(bao.toString());
//         6. 关流
        fis.close();
    

c.
    随机访问流  --RandomAccessFile
        概述
            * RandomAccessFile 不属于流,而是Object中的子类
            * 只是封装了 InputStream 和 OutputStream 的功能而已,支持对随机访问流的 读 和 写。
        
        构造方法
             RandomAccessFile(String name, String mode);
                 * 参数一: 读路径的字符串表现形式
                 * 参数二: mode 参数指定用以打开文件的访问模式。
                     * r(读), rw(读写), rws, rws     
             RandomAccessFile(File name, String mode);
                * 参数一: 读路径的File的表现形式
                 * 参数二: mode 参数指定用以打开文件的访问模式。
                     * r(读), rw(读写), rws, rws     

        目的:支持一个多线程下载,提高效率

d.
    对象操作流 --ObjectOutputStream ObjectInputStream
        (写入的文件是看不懂的,只要读取的时候能读出来就可以了)
        概述
            * 该类可以将对象写入,或读取一个对象到程序中,也就是执行了 对象的 序列化 和 反序列化 操作。
                * 将对象写入到文件中(序列化 --ObjectOutputStream)
                * 从文件中读取对象到程序中 (反序列化 --ObjectInputStream)
        使用
            * 序列化 写入
                * new ObjectOutputStream   writerObject();
                * 前提:对象必须实现序列化Serializable 接口 
                
            * 反序列化 读取
                * new ObjectInputStream readObject();
            
        对象操作流的优化
            * 采用集合的方式将写入的对象进行存储
            * 在读取时,读取集合将集合遍历即可
        
        一个类实现了 Serializable 接口之后,会报黄色的警告线,怎么解决?
        给该类加一个 UID 号就可以。
        Serializable 用于给被序列化的类加入ID号,用于判断类和对象是否是同一个版本
        示例:
            private static final long serialVersionUID = 1L;


e.
    数据输入输出流 --DataOutputStream DataInputStream
        (写入的文件是看不懂的,只要读取的时候能读出来就可以了)
        概述
            * 因为字节流 和 字符流 在读写数据时只能按照字节或字符来读写,不能一次读写一个基本数据类型,会出现乱码。
            * DataInputStrem, DataOutputStream可以按照基本数据类型大小进行读写数据
                * 如:按Long类型大小写出一个数字,写出时该数据占8个字节,而读取的时候也可以按照Long类型读取,也一次性读取8个字节
        
        使用
            * DataOutputStream(OutputStream)   
                * writeInt();    
                * writeLong();
            * DataInputStream(InputStream)    
                * readInt();
                * readLong();
            
基本数据类型有 隐式转换 和 强制类型转换 的特点
引用数据类型有 向上转型 和 向下转型 的特点


f.
    打印流 --PrintStream (打印字节流)
        概述
            * 该流可以很方便的将对象的toString()结果进行打印输出,并且加入自动换行功能,而且还可以使用自动刷出的模式
            * System.out 其实就是一个PrintStream(打印流),其默认向控制台输出结果信息
            * 打印流只操作数据目的 的 【目的地文件】
        
        使用方式
            * 打印 print() 和 println();
            * 自动刷出:PrintWriter(OutputStream out, boolean autoFlush) 打印字符流

        注意
            * PrintStream 字节打印流
                * System.out(标准输出流,默认指向控制台),它是PrintStream类型的。
                
            * PrintWriter 字符打印流
                * public PrintWriter(OutputStream os, boolean autoFlush);,如果传入true,可以自动启动刷新功能, 自动刷新功能只针对 println()方法有效。
        作用
            * 该流可以很方便的将对象的toString()输出到控制台,并且可以启用自动刷新和换行功能。
            * PrintStream 和 PrintWriter 分别打印的是字节流和字符流。
            * 两个都操作的是数据目的(目的地文件)。

g.
    标准输入输出流(改变标准输入输出流)
        概述
            * System.in  是 InputStream 标准输入流。默认从键盘输入数据,读取字节数据。(可以接收键盘录入的数据)
            * System.out 是 OutputStream 标准输出流。默认可以向键盘中输出字符和字节数据。(可以往控制台写出数据)
            
        修改标准输入输出流
            * 修改输入流: System.setIn(InputStream) 可以改变标准输入流的指向(由原来默认指向的键盘,变成了现在指向了文件)
            * 修改输出流: System.setOut(PrintStream) 可以改变标准输出流的指向(由原来默认指向的控制台,变成现在指向了文件)

        代码
        System.setIn(new FileInputStream("改变标准输入流.txt")); //改变原来的标准输入流(由原来默认指向键盘,变成现在指向文件)
        System.setOut(new PrintStream("改变标准输出流.txt"));  //改变原来的标准输出流(由原来默认指向控制台,变成现在指向文件)
        InputStream in = System.in;  //获取标准的键盘输入流 默认指向键盘,改变后指向文件
        PrintStream out = System.out; //获取标准的键盘输出流 默认指向控制台,改变后指向文件
        
        int r;
        while(( r = in.read()) !=-1){
            out.write(r);
        }
        
        in.close();
        out.close();

    
    修改标准输入输出流来拷贝图片
        System.setIn(new FileInputStream("timg.jpg"));  //改变标准的输入流
        System.setOut(new PrintStream("copy_timg.jpg")); //改变标准的输出流
        
        InputStream in = System.in;         //改变后,由原来默认指向的键盘,变成了现在指向了文件
        OutputStream out = System.out; //改变后,有原来默认指向的控制台,变成了现在指向了文件
        
        int r;
        byte[] b = new byte[8192];
        while(( r = in.read(b)) != -1){
            out.write(b, 0, r);
        }
        in.close();
        out.close();
    
    
    两种方式实现键盘录入
        * 方式一:Scanner
            * Scanner sc = new Scanner(System.in);
            * String nextLine = sc.nextLine();  //只可以读取字符串
            * System.out.println(nextLine); 
            * sc.close();
        * 方式二:转换流的方式
            * BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            * String readLine = br.readLine();
            * System.out.println(readLine);
            * br.close(); //也可以不用关

h.
    Properties
        概述
            * 其实是一个双列集合,常作为 配置文件 被使用,使用流对象去读取该配置文件,来和程序产生关联
            * Properties类 表示一个持久的属性集,也是一个配置文件
            * Properties类 可以保存在流中或从流中加载
            * 属性列表中的键和值值都是String类型
            * Properties是Hashable的一个子类(Hashable已经被HashMap代替)
            * Properties是唯一一个可以和IO流结合使用的集合类

        特殊功能方法
            特殊功能方法
            * public Object setProperty(String key, String value); 调用 Hashtable 的方法 put。
            * public String getProperty(String key); 用指定的键在此属性列表中搜索属性。
            * public Enumeration<String> propertyNames()返回属性列表中所有键的枚举,如果在主属性列表中未找到同名的键,则包括默认属性列表中不同的键。 


i.
    Properties中的load()和store()方法
        * load(InputStream inStream) 从输入流中读取属性列表(键和元素对)。
            * 操作字节流
            * 从流(配置文件) 中读取数据到集合中
        * load(Reader reader) 按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。
            * 操作字符流
            * 从输入流中读取属性列表
        

        * store(OutputStream out, String comments) 以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。
            * 操作字节流    
            * 将集合中的数据写入到配置文件中

        * store(Writer writer, String comments) 以适合使用 load(Reader) 方法的格式,将此 Properties 表中的属性列表(键和元素对)写入输出字符。
            * 操作字符流
            *  第二个参数,是对列表参数的描述(可以给值,也可以是null)

【流的操作规律】
之所以要弄清楚这个规律,是因为流对象太多,开发时不知道具体该使用哪个合适
要想知道对象再开发时要使用到哪些对象,只要通过四个明确即可。
1、明确源和目的地
        源:InputStream         Reader
      目的:OutputStream        Writer

2、明确操作的数据是否是纯文本
      源:是纯文本:Reader
                否:InputStream
    目的:是纯文本:Writer
            否:OutputStream
到这里,就可以明确需求中具体要使用哪个体系。

3、明确具体操作设备
    源文件:
        硬盘:File
        键盘:System.in
        内存:小数组
        网络:Socket流
    目的地:
        硬盘:File
        控制台:System.out
        内存:小数组
        网络:Socket流

4、是否需要其他额外功能
    是否需要高效(缓冲区):
        是,就加上Buffer



UTF-8编码中,一个中文占3个字节
ASCII编码中,一个中文占2个字节

什么时候使用转换流?
    1、源文件或目的地对应设备是字节流,而操作的数据是文本数据,那么就要使用到桥梁,提高对文本的操作效率。
    2、一旦操作文本涉及到具体指定码表时,必须使用转换流


【字节流继承体系图】
字节流
    * InputStream
        * FileInputStream
        * FilterInputStream
            * BufferedInputStream
    * OutputStream                                    
        * FileOuptStream
        * FilterOutputStream
            * BufferedOutputStream

【字符流继承体系图】
    * Reader
        * InputStreamReader
            * FileReader
        * BufferedReader
        
    * Writer
        * OutputStreamWriter
            * FileWriter
        * BufferedWriter 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值