A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

© tianhaolin 初级黑马   /  2018-11-26 15:21  /  762 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

一、IO流       
1.字节流:可以读取任意的文件
2.字节输出流:OutputStream
  1)基本方法:
     *void close()
        关闭此输出流并释放与此流有关的所有系统资源。
     *void flush()
         刷新此输出流并强制写出所有缓冲的输出字节。
     *void write(byte[] b)
         将 b.length 个字节从指定的 byte 数组写入此输出流。
     *void write(byte[] b, int off, int len)
         将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
     *abstract void write(int b)  
         将指定的字节写入此输出流。
  2)FileOutputStream extends OutputStream
     *构造方法:
            FileOutputStream(String name)
                   创建一个向具有指定名称的文件中写入数据的文件输出流
                FileOutputStream(File file)
                   创建一个向指定File对象表示的文件中写入数据的输出文件流
                   参数:写入数据的目的
                     String name:目的地是一个文件的路径
                         File file:目的地是一个文件的文件
                   构造方法的作用
                     创建一个FileOutputStream对象
                         会根据构造方法中传递的文件/文件路径,创建一个空的文件
                         会把FileOutputStream对象指向创建好的文件
         *字节输出流的的使用步骤
               **创建一个FileOutputStream对象,构造方法中传递写入数据的目的地
                **调用FileOutputStream对象中的方法write,把数据写入到文件中
                **释放资源(流会占用一定的内存,使用完毕要把内存清空,提高程序的效率
         *文件写入原理
           .write(int b) 会把十进制的整数转换为二进制的整数
           任意的文本编辑器(记事本,notepad++)在打开文件的时候,都会查询编码表,把字节转换为字符表示
             0-127:查询ASCII表
                 其他值:查询系统默认码表(中文系统是GBK)
        *写入多个字节的方法
             **void write(byte[] b)
             **void write(byte[] b, int off, int len)
             注意: 如果写的第一个字节是正数,那么现实的时候回查询ASCII表
                 如果写的第一个字节是负数,那第一个字节会和第二个字节(每一对字节)组成一个中文显示,查询GBK(中文系统默认码表)
         *写入字符串的方法:
              可使用String类中的方法把字符串转换为字节数组
              Byte[] getBytes()
         *数据的追加和换行-FileOutputStream特有的构造方法
             **追加
                 FileOutputStream(String name,boolean append)
                 FileOutputStream(File file,boolean append)
                 参数append:追加写开关
            **换行
              write("/r/n".getBytes)
                 
3.字节输入流:InputStream
   1)基本方法:
     *int read() 从输入流中读取数据的下一个字节
         *int read(bytr[] b)从输入流中读取一定数量的字节,并将其存储在缓冲数组b中
         *void close()关闭输入流并释放其关联的所有系统资源
   2)FileInpuStream extends InputStream
     *构造方法
           FileInputStream(String name)
           FileInpuStream(File file)
           构造方法的作用:
              创建一个人FileInputStream对象
              会把FileInputStream对象制定构造方法中要读取的文件
         *读取文件(固定写法)
               while(len =file.read()!=-1){
                 Systrm.out.print((char)len);
                  }
         *字节输入流一次读取多个字节的方法:int read(byte[] b)
           必须明确的两件事情:
             **方法的参数byte[]的作用
                   起到BUFFER作用,存储每次读取到的多个字节
                   数组的长度一般定义为1024或者是1024的整数倍
             **方法返回值int是什么
                   返回读取到有效数据的长度,如果有效数据长度为0则返回-1
        3)字节流的问题
           使用字节流读取中文文件,每次只能读取一个字节,会得到乱码
              1个中文->GBK:占用两个字节
                         ->UTF-8:占用3个字节
                               
4.字符输入流:Reader
   1)基本方法:
     *int read() 从字符输入流中读取数据的下一个字符
         *int read(bytr[] b)从输入流中读取一定数量的字节,并将其存储在缓冲数组b中
         *void close()关闭输入流并释放其关联的所有系统资源
   2)FileReader
     *构造方法
           FileReader(String name)
           FileReader(File file)
     *读取文件(固定写法)
           while(len =file.read()!=-1){
             Systrm.out.print((char)len);
                 }
     *缓冲读取多个字节的方法:int read(char[] b)
         必须明确的两件事情:
          **方法的参数byte[]的作用
                起到BUFFER作用,存储每次读取到的多个字节
                数组的长度一般定义为1024或者是1024的整数倍
         **方法返回值int是什么
                返回读取到有效数据的长度,如果有效数据长度为0则返回-1
                  
5.字符输出流:Writer
    1)基本方法
     *void close()
        关闭此输出流并释放与此流有关的所有系统资源。
     *void flush()
         刷新此输出流并强制写出所有缓冲的输出字节。
     *void write(char[] b)
         将 b.length 个字节从指定的 char 数组写入此输出流。
         *void write(char[] b, int off, int len)
         将指定 char 数组中从偏移量 off 开始的 len 个字节写入此输出流。
     *abstract void write(int b)  
         将指定的字节写入此输出流。
2)FileWriter
    *构造方法
          FileInputStream(String name)
          FileInpuStream(File file)
     *字符输出流的的使用步骤
            **创建一个FileWriter对象,构造方法中传递写入数据的目的地
            **调用FileWriter对象中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)
            **使用FileWriter中的flush,把内存缓冲区中的数据,刷新到文件中
            **释放资源(流会占用一定的内存,使用完毕要把内存清空,提高程序的效率
               注意:当调用void close()方法时,会强制输出内存缓冲区的内容
    *close()和flush()的区别
            -flush方法:刷新缓冲区,流对象可以继续使用
            -close方法:先刷新缓冲区,然后通知系统释放资源,流对象不可以再被使用
    *写入字符的其他方法:
            -void write(char[] cbuf) 写入字符数组
            -void write(char[] cbuf,int off,int len); 写入字符数组的一部分(off)开始,(len)长度
            -void write(String str)
            -void write(String str,int off int len); 写入字符串的一部分(off)开始,(len)长度
     *字符流的续写和换行-和字节流一样
          
6.IO异常的处理
   1)JDK7之前的处理
     使用try...catch...final处理流中的异常--非常麻烦
         FileWriter fileWriter = null;
        try {
             fileWriter = new FileWriter(path,true);
             fileWriter.write(String str);
        }catch(IOException e){
            e.printStackTrace();
        }finally{
                   if(fileWriter !=null){
             try {
                 fileWriter.close();
             } catch (IOException e) {
                 e.printStackTrace();
             }
           }
                }
   2)JDK7新特性-try(定义流对象){读取的代码}...catch...
     以上的代码可以写为
          try(fileWriter = new FileWriter(path,true);){
              fileWriter.write(String str);
            }catch(IOException e){
            e.printStackTrace();
                        }
         注意:在try后边增加一个(),在括号中可以定义流对象
              那么这个流对象的作用域就在括号中,当代码执行结束后,会把流自动释放
                  所以不用写close()
   3)JDK9新特性
     try的前边可以直接定义流对象,在try后边的括号()中可以直接引入流对象(变量名)
         在try代码执行完毕之后,流对象也可以释放掉,不用写finally和close;
         注意:创建的资源必须是final修饰或者是有效final(不再次赋值)的
   4)JDK9的使用场景
   
       
7.属性集-表示一个永久的属性集,它使用键值结构存储数据
  1)Properties extend HashTable<k,v> implementd Map<k,v>
    *表示了一个持久的属性集,可保存在流中或从流中加载,属性列表中的每一个值都是一个字符串
    *是唯一一个与IO流结合的集合
         **可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中储存
         **可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用
    *Properties集合存储数据/取出数据
         **Object setProperty(String key,String value) 调用Hashtable的方法Put
         **String getProperty(String key) 通过key找到value值,此方法相当于Map集合中的get方法
         **Set<String> stringPropertyNames() 返回属性列表中的键集,相当于Map集合中的keySet方法
     
   2)Properties集合中的store方法-将Properties集合中的数据放入硬盘中保存
     *方法:
       **void store(OutputStream out,String comments)
       **void store(Writer writer,String comments)
      **参数:
           OutputStream out:字节输出流不能写入中文
           Writer writer:字节输出流,可以写中文.
           String comments:注释,用来解释保存文件是做什么用的(一般使用空字符串)
                                 不能使用中文,会产生乱码,因为其默认为Unicode编码
    *使用步骤:
           创建一个Properties集合对象,添加数据
           创建字节流/字符流输出对象,构造方法中绑定要输出的目的地
           使用Properties集合中的方法store,把集合中的临时数据持久化写入到硬盘中存储
           释放资源
               
   3)Properties集合中的load方法-将文件中的键值对读取到集合中使用
     *方法:
           **void load(InputStream inStream)
           **void load(Reader reader)
           **参数:
                  Input Stream inStream:字节流输入,不能读取有中文的键值对
                  Reader reader:字符流输入,可以读取含有中文的键值对
    *使用步骤:
            创建一个Properties集合对象
            使用Properties集合对象中的方法load读取保存键值对的文件
            遍历Properties集合
    *注意事项
             存储键值对的文件中,键与值默认的连接符号可以使用=,空格(其他符号)
                    例: 键 值/键$值
             存储键值对的文件中,可以使用#进行注释,被注释的键值对不会再被读取
             存储键值对的文件中,键与值默认都是字符串,不用再加""

二、缓冲、转换、序列化、打印流
注:都是包装流,并不是真正的输入输出流
问题:缓冲输入流如何提高效率?InputStream中的int read(byte[] bytes)是自己创建一个缓冲区
     和BufferedInputStream有什么区别?其内存关系是怎么样的?


1.缓冲流
1)字节缓冲流
    *BufferedOutputStream extends OutputStream
           **继承自父类的方法:
        -0void close()
           关闭此输出流并释放与此流有关的所有系统资源。
        -void flush()
          刷新此输出流并强制写出所有缓冲的输出字节。
        -void write(byte[] b)
          将 b.length 个字节从指定的 byte 数组写入此输出流。
        -void write(byte[] b, int off, int len)
          将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
        -abstract void write(int b)  
          将指定的字节写入此输出流。
           **构造方法:
            -BufferedOutputStream(OutputStream out):
                  创建一个新的缓冲输出流,以将数据写入指定的低层输出流
            -BufferedOutputStream(OutputStream out,int size)
                  创建一个新的缓冲输出流,并指定大小,以将数据写入指定的低层输出流
           **使用步骤(重点)
                -创建FileOutputStream对象,构造方法中绑定要输出的目的地
                -创建BufferedOutputStream对象,构造方法中传递FileInput对象,提高FileOutputStream对象的效率
                -使用BufferedOutputStream对象中的方法write,把数据写入到内部缓冲区中
                -使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据,刷新到文件中
                -释放资源(第四步可以省略)
       
    *BufferedInputStream extends InputStream
         **构造方法
          -BufferedInputStream(InputStream in): 使用基本流创建一个缓冲字节输入流
          -BufferedInputStream(InputStream in, int size): 使用基本流创建一个缓冲字节输入流, 设置缓冲区大小

2)字符缓冲流
    *BufferedWriter extends Writer
          **构造方法
           -BufferedWriter(Writer out): 使用基本流创建一个缓冲字符输出流
           -BufferedWriter(Writer out, int size): 使用基本流创建一个缓冲字符输出流, 设置缓冲区大小
          **特有方法
           -void newLine(): 写入一个换行符, 换行符自动根据当前系统确定
       
    *BufferedWriter extends Writer
          **构造方法
            -BufferedReader(Reader in): 使用基本流创建一个缓冲字符输入流
            -BufferedReader(Reader in, int size): 使用基本流创建一个缓冲字符输入流, 设置缓冲区大小
          **特有方法
            -String readLine(): 一次读一行字符串, "不包含换行符". 读到文件末尾返回null
       
2.转换流--防止读取乱码问题
1)字符编码和字符集
    *字符编码和解码-一套自然语言和二进制数质检的对应规则
          编码:字符(能看懂的)->字节(看不懂的)
          解码:字节(看不懂的)->字符(看得懂的)
        *字符集
          包含编码表,是一个系统支持的所有字符的集合,一套字符集必须包含一套编码表
          常用码表:ASCII字符集/GBK字符集/Unicod字符集(UTF8编码,UTF16编码,UTF32编码)
        *常用字符集:
          ISO-8859-1 没有中文的编码表
          UTF-8:通用编码
          GBK:中文系统默认编码表
        *编码引出的问题:
          当读取的编码和存储的编码不一致时,会引发乱码问题
2)转换流原理:
        *使用字节流读取字节,根据默认(或给定)的码表转换为字符
        *FileReader是InputStreamWriter的子类,它只可以使用系统默认的码表
3)输出转换流
      *OutputStreamWriter类: 输出转换流. 字符流通往字节流的桥梁
          **构造方法
            -OutputStreamWriter(OutputStream out): 使用默认编码表创建转换流
            -OutputStreamWriter(OutputStream out, String charsetName): 使用指定编码表创建转换流
               charseName:"GBK","UTF-8","ISO-8859-1"
4)输入转换流
    *InputStreamReader类: 输入转换流. 字节流通往字符流的桥梁
          **构造方法
            -InputStreamReader(InputStream in): 使用默认编码表创建转换流
            -InputStreamReader(InputStream in,?String charsetName): 使用指定编码表创建转换流
       
3.序列化流(对象流)
1)序列化和反序列化
   *对象的序列化:把对象以字节流的方式写入到文件中保存
   *对象的反序列化:把文件中的对象使用字节流读取出来
   注意:Serializable接口也叫标记型接口
        当我们进行序列化的时候,就会检测类上是否有这个标记
        如果实现了Serializable接口,就可以序列化和反序列化
        如果未实现Serializable接口,则会抛出NotSerializableException
   
2)java.io.ObjectOutputStream类: 对象字节输出流
        *构造方法
          -ObjectOutputStream(OutputStream out)
        *特有成员方法
          -void writeObject(Object obj): 将对象写出
       
3)ObjectInputStream类: 对象字节输入流
        *构造方法
          -ObjectInputStream(InputStream in)
        *特有成员方法
          -Object readObject(): 读取对象
       
4)瞬态关键字-transient
    *static关键字修饰的属性(成员变量)不能被序列化
        *transient关键字修饰的属性也不能被序列化,但是不具备static的属性


5)【重要】InvalidClassExcption异常:原因和解决办法
    *如果将对象序列化到文件中后,代码中的类发生了变化,那么反序列化会失败抛出InvalidClassException
         **原因:编译期会把类文件(如Person)编译称为class,因为Person类实现了Serializeable接口,
                  会根据类的定义给Person.class文件添加一个序列号:serialVersionUID = -??????
                  当类被修改后,重新生成一个新的序列号
         **解决方法:当定义一个可序列化的类时,人为添加一个serialVersionUID字段
                    该字段必须是(private) static final long serialVerionUID = 数字L;
            
4.打印流
1)PrintStream extens OutputStream 字节打印流
     *构造方法
        -PrintStream(File file): 创建字节打印流, 输出到一个文件
        -PrintStream(OutputStream out): 创建字节打印流, 输出到一个字节输出流
        -PrintStream(String fileName): 创建字节打印流, 输出到一个文件路径
     *特点:
        -只负责数据的输出,不负责数据的读取
        -永远不会抛出IOException
        -特有的方法:print和println方法
         注意:如果使用继承自父类的write方法写数据,那么查看数据的手会查询编码表
              如果使用特有的方法写数据,那么写的数据原样输出.
         


2)java.lang.System类:
*静态方法
        static void setOut(PrintStream out): 设置System.out的输出目的地为参数的打印流
   

您需要登录后才可以回帖 登录 | 加入黑马