zoukankan      html  css  js  c++  java
  • 基础知识之----------IO流(1)

    1、IO流

      用于将存储设备中的数据(硬盘、内存等)读入到固定设备中进行处理。

      IO流分为字节流和字符流。

      之前是没有字符流的,有ASICC编码表,里面固定的数字代表各个字母。但是每个国家的信息是不同的,就造成各个国家有各自的码表,不利于信息的互通。

      后来产生了国际通用码表,可以识别很多国家的文字。Unicode码表。特点是:不论什么字符都用两个字节表示。

      一个中文在GBK中数字和Unicode中可能并不一样。

      Unicode对所有文字进行了重新编码。所以在GBK中编写了,使用Unicode码表查看可能就不是原来的文字了。

      字符流:是指字节流读取文字字节数据后,不直接操作而是先查询指定的编码表然后获取对应的文字。再对这个文字进行操作。简单说就是:字节流+编码表。

      字节流的两个顶层父类:1、InputStream   2、OutputStream

      字符流的两个顶层父类:1、Writer   2、Reader

      

      如果要操作文字数据,优先考虑字符流。

      而且要将数据从内存写到硬盘上。要使用字符流中的输出流。

    1.1测试流----写

      

        /**
         * 创建一个可以往文件中写入字符数据的字符输出流对象
         * 既然是往一个文件中写入文字数据,那么在创建对象时,就必须明确该文件(用于存储数据的目的地)
         * 如果文件不存在,则会自动创建
         * 如果文件存在,则会被覆盖
         * @param args
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            FileWriter writer=new FileWriter("d://demo.txt");
            /**
             * 调用Writer对象中的write(String)方法,写入数据。
             * 数据在write方法执行后,其实已经写入到了临时存储缓冲区中,流里面。
             * flush,刷新该流的缓冲。如果该流已保存缓冲区中各种write()方法的所有字符,则立即将它们写入预期目标。然后,如果该目标是另一个字符或字节流,则将其刷新。
             * 因此,一次刷新调用将刷新writer和OutputStream链中的所有缓冲区。
             * 刷新,将数据直接写入到目的地中。
             */
            writer.write("测试");
            writer.write("123");
         writer.flush(); writer.close(); }

      关闭和刷新有什么区别呢?close是先刷新后关闭资源。flash是不关闭资源。

      闭关就是无法再刷入文件了,而刷入可以再刷。

      可以关联Windows的文本文件的打开、编辑、关闭。

      关闭后再打开,将会是一个新的流。其实java流写入也是调用Windows的写入。

    (2)字符流FileWriter的换行、续写。

      在Windows中“ ”是换行。

      那如果换个系统怎么办。

     定义一个常亮,自动获取当前系统的换行符。 

    private static final String LINE_SEPARATOR =System.getProperty("line.separator") ;
    writer.write("测试"+LINE_SEPARATOR);
    (3)续写
    在一个流写入完之后,怎么在上一个文件的基础上增加呢?而不是覆盖掉原来的内容。
    FileWriter(String fileName, boolean append) 
              根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。

    在构造的时候添加true

     FileWriter writer=new FileWriter("d://demo.txt",true);

    就可以开启续写功能。

    (4)IO异常处理

    public static void main(String[] args)  {
            FileWriter writer=null;
            try {
                writer = new FileWriter("ds://demo.txt", true);
                /**
                 * 调用Writer对象中的write(String)方法,写入数据。
                 * 数据在write方法执行后,其实已经写入到了临时存储缓冲区中,流里面。
                 * flush,刷新该流的缓冲。如果该流已保存缓冲区中各种write()方法的所有字符,则立即将它们写入预期目标。然后,如果该目标是另一个字符或字节流,则将其刷新。
                 * 因此,一次刷新调用将刷新writer和OutputStream链中的所有缓冲区。
                 * 刷新,将数据直接写入到目的地中。
                 */
                writer.write("测试" + LINE_SEPARATOR);
                writer.write("1231");
    
            }catch (IOException e){
                System.out.println(e.toString());
            }finally {
                if (writer!=null)
                try {
                    writer.close();
                } catch (IOException e) {
                   throw new RuntimeException("关闭失败");
                }
            }
        }
    View Code

     需要在try/catch外先声明FileWriter,在try/catch内初始化。

    close要独立捕获异常。

    (5)FileReader字符流读取方式

      找到FileReader

      数据在存储的时候都有头和尾标识。

      read读取单个字符。在字符可用、发送I/O错误或者已达到流的末尾前,此方法一直阻塞。

      用于支持高效的单字符输入的子类应重写此方法。

      返回:作为整数读取的字符,范围在0到6 5535之间,如果已到达流的末尾,则返回-1.

      

            //创建一个读取字符流对象,在创建读取流对象时,必须要明确被读取的文件。一定要确定该文件是存在的。
            //用一个读取流关联一个已存在文件。
            FileReader fr = new FileReader("d:/demo.txt");
            int ch = fr.read();
            System.out.println( ch);
            int ch1 = fr.read();
            System.out.println((char) ch1);
            fr.close();

      以上方法只能一次读取一个字符。

      

            //创建一个读取字符流对象,在创建读取流对象时,必须要明确被读取的文件。一定要确定该文件是存在的。
            //用一个读取流关联一个已存在文件。
            FileReader fr = new FileReader("d:/demo.txt");
            int ch = 0;
            while ((ch=fr.read())!=-1){
                System.out.print((char)ch);

    遍历读取,但是依然是一个个的读取。

      读取方式二:

      num返回的是读取字符的个数。

      第一个buf读取前三个,第二次读取读最后两个,但是依然是使用buf,此时只有前两个改变。最后一个字符是上次读取的。第三次并没有读取。

      read取肯定是一个个取的。

     2、缓冲区

      提高效率。

      缓冲区在创建对象时必须有被缓冲的对象,就好像(没有饭要碗有什么用)。缓冲区的对象为流。

        方法摘要:newLine写入一个行分隔符,write(int c)写入单个字符。write(String s,int off,int len)写入字符串的一部分

      BufferedWriter的方法close,其实是把流的close方法封装了。

      

        public static void main(String[] args) throws IOException {
            FileWriter fw=new FileWriter("d://dem.txt");
            BufferedWriter bw=new BufferedWriter(fw);
            bw.write("你哈啊 啊啊 啊");
            bw.newLine();
            bw.write("1");
            bw.flush();
            bw.close();

    (2)BufferedReader

      其中有一个readLine ,是按行读取。

      

        public static void main(String[] args) throws IOException {
           FileReader fr=new FileReader("d://dem.txt");
           BufferedReader br=new BufferedReader(fr);
           String line=null;
           while ((line=br.readLine())!=null){
               System.out.println(line);
           }
        }

    注意readLine最好先付给一个string变量,不然会显示不了第一行。

      bufr.read()这个是从缓冲区中的取出的字符数据。所以覆盖了父类中的read方法。

      例子:去厨房拿馒头,使用流是一个个拿。现在使用缓冲区,就是相当于拿了一个框去拿馒头,一次拿一筐。那么取馒头的时候当然要从框(缓冲区)里取出来。

      已经不需要从硬盘读,而是读内存中的数据。所以已经高效了。buffuedreader的read方法覆盖了父类的read方法,从内存读。

      

      readLine();使用了读取缓冲区中的read方法,将读取到的字符进行缓冲并判断换行标记。将标记前的缓存数据变成字符串返回。

      这个容器也可以是StringBuilder,因为最终返回的是字符串。

      

    流创建,缓冲区关联流。

      

           while ((line=br.readLine())!=null){
               bw.write(line);
               bw.newLine();
               bw.flush();
           }
    

      

    3、缓冲区之装饰设计模式

      缓冲区,将数据进行了缓存并对其数组进行了操作。提高了效率。

      装饰设计模式:对一组对象的功能进行增强时,就可以使用该模式进行问题的解决。

      

    package test;
    
    public class Person {
        public static void main(String[] args) {
            Per person=new Per();
    //        person.chifan();
            NewPer p1=new NewPer(person);
            p1.chifan();
            NewPer2 p2=new NewPer2();
            p2.chifan();
        }
    }
    
    class Per{
        void chifan(){
            System.out.println("吃饭");
        }
    }
    
    class NewPer{
        private Per pe;
        NewPer(Per pe){
            this.pe=pe;
        }
        public void chifan(){
            System.out.println("开胃酒");
            pe.chifan();
            System.out.println("甜点");
        }
    }
    
    class NewPer2 extends Per{
        public void chifan(){
            System.out.println("开胃酒");
            super.chifan();
            System.out.println("甜甜");
        }
    }
    View Code

    4、装饰设计模式和继承很相似,但是区别有哪些呢?

    首先有一个继承体系。

      想要对操作的动作进行效率的提高。

      按照面向对象,可以通过继承对具体的进行功能的扩展。

      效率提高需要加入缓冲技术。

      比如要新增一个小功能。那么可以使用继承,添加一个方法。

      但是如果这个体系进行了功能扩展,又多了一个功能。

      那么这个功能要提高效率,是不是也要产生子类呢?是,这个时候就会发现只为提高功能,进行的继承。导致继承体系越来越臃肿。不够灵活

      重新思考:

      既然加入的都是同一种技术---缓冲。

      前一种是让缓冲和具体的对象相结合。

      可不可以将缓冲进行单独的 封装,那个对象需要缓冲就将那个对象和缓冲关联。  

      

    装饰比继承更为灵活,不需要产生关系。

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

    5、

      

      LineNumberReader是缓冲区的子类,具备了装饰功能。覆盖了父类和父类的一些功能。

     

    6、以上说的基本都是字符流,字节流与字符流类相同,但它不近可以操作字符,还可以操作其他媒体文件。

      字节流不需要编解码,不需要进行临时缓冲的。而是直接写入到目的地中。

      

        public static void main(String[] args) throws IOException {
            //1、创建字节流输出流对象,用于操作文件
            FileOutputStream fos=new FileOutputStream("demo.txt");
    //        2、写数据
            fos.write("测试信息".getBytes());
            //关闭资源动作要完成
            fos.close();
        }
        public static void main(String[] args) throws IOException {
            FileInputStream fis=new FileInputStream("d://dem.txt");
            byte[] buf=new byte[1024];
            int len=0;
            while ((len=fis.read(buf))!=-1){
                System.out.println(new String(buf,0,len));
            }
        }

      fis.available();获取文件的 大小

      示例:

        public static void main(String[] args) throws IOException {
            FileInputStream fis=new FileInputStream("d://dem.txt");
            byte[] buf=new byte[fis.available()];
            fis.read(buf);
            System.out.println(new String(buf) );

    一个刚刚好的数组

      使用缓冲区的时候不要忘记flash();

      为什么字符流不可以复制图片。读完后再写。字符流的特点在于,读完了字节数据后并没有往目的中写,而是查询了表。

      那么如果字节数据在表里没有查到内容,文字有特定编码格式。而图片并没有,如果在码表内未查找到对的编码格式。则无法解析。会出错   

    坚持就是胜利
  • 相关阅读:
    设计模式 策略模式
    Java 集合 LinkedList的ListIterator
    Java 集合 JDK1.7的LinkedList
    Java 集合 集合与数组之间的转换
    Java Object 对象拷贝答疑
    Java Object 对象拷贝
    Java 集合 fail-fast机制 [ 转载 ]
    .net知识点汇总
    Javascript知识点汇总-初级篇
    Javascript实用技巧
  • 原文地址:https://www.cnblogs.com/xiaotieblog/p/8430836.html
Copyright © 2011-2022 走看看