• Java IO(一)


       字节流的两个基类:

    1. InputStream
    2. OutputStream

       字符流的两个基类:

    1. Reader
    2. Writer

       Writer

       先学习一下字符流的特点。

       既然IO流是用于操作数据的,那么数据的最常见体现形式是:文件。那么先以操作文件为主来演示。

       例,需求:在硬盘上,创建一个文件并写入一些文字数据。

       分析:

       找到一个专门用于操作文件的Writer子类对象——FileWriter,后缀名是父类名,前缀名是该流对象的功能

       步骤:

    1. 创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件。而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。其实该步骤就是在明确数据要存放的目的地。
    2. 调用write(),将字符串写入到流中。
    3. 刷新流对象中的缓冲区中的数据,将数据刷到目的地中。
    4. 关闭流资源,但是关闭之前会刷新一次内部的缓冲区中的数据。将数据刷到目的地中。和flush()区别:flush刷新后,流可以继续使用,close()刷新后,会将流关闭。   

       示例代码如下:

    import java.io.FileWriter;
    import java.io.IOException;
    
    public class FileWriterDemo0 {
    
        public static void main(String[] args) throws IOException {
            //创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件
            //而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
            //其实该步骤就是在明确数据要存放的目的地。
            FileWriter fw = new FileWriter("demo.txt");
            
            //调用write(),将字符串写入到流中
            fw.write("abcde");
            
            //刷新流对象中的缓冲区中的数据,将数据刷到目的地中。
            //fw.flush();
            
            /*
             * 关闭流资源,但是关闭之前会刷新一次内部的缓冲区中的数据。
             * 将数据刷到目的地中。
             * 和flush()区别:flush刷新后,流可以继续使用,close()刷新后,会将流关闭。
             */
            fw.close();
            
            fw.write("haha");
        }
    
    }

       IO异常的处理方式:

       示例代码:

    /*
    IO异常的处理方式。
    最后无论如何都应关闭资源,所以应放在finally代码块中
    */
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class FileWriterDemo1 {
    
        public static void main(String[] args) {
            FileWriter fw = null;
            try {
                fw = new FileWriter("demo.txt");
                fw.write("abcdefg");
            } catch (IOException e) {
                System.out.println("catch:" + e.toString());
            } finally {
                try {
                    if(fw != null) 
                        fw.close();
                } catch (IOException e) {
                    System.out.println(e.toString());
                }
            }
            
        }
    
    }

       对已有文件的数据续写:

       示例代码:

    /*
    演示对已有文件的数据续写。
    */
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class FileWriterDemo2 {
    
        public static void main(String[] args) throws IOException {
            /*
             * 传递一个true参数,代表不覆盖已有的文件。
             * 并在已有文件的末尾处进行数据续写。
             * 
    在windows中表示行终止符
             */
            FileWriter fw = new FileWriter("demo.txt", true);
            
            fw.write("nihao
    xiexie");
            
            fw.close();
        }
    
    }

       Reader

       例,需求:从硬盘的一个文件中读取内容

       代码:

    import java.io.FileReader;
    import java.io.IOException;
    
    public class FileReaderDemo0 {
    
        public static void main(String[] args) throws IOException {
            /*
             * 创建一个文件读取流对象,和指定名称的文件相关联。
             * 要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException。
             */
            FileReader fr = new FileReader("demo.txt");
            
            /*
             * 调用读取流对象的read()
             * read():一次读取一个字符,会自动往下读。
             */
            int ch = 0;
            while((ch = fr.read()) != -1) {
                System.out.println((char)ch);
            }
            /*
            while(true) {
                int ch = fr.read();
                if(ch == -1) 
                    break;
                System.out.println("ch = " + (char) ch);
            }
            */
            
            fr.close();
        }
    
    }

       图示:

       第二种方式:通过字符数组进行读取。

       示例代码如下:

    /*
    第二种方式:通过字符数组进行读取。
     */
    import java.io.FileReader;
    import java.io.IOException;
    
    public class FileReaderDemo1 {
    
        public static void main(String[] args) throws IOException {
            FileReader fr = new FileReader("demo.txt");
            
            /*
             * 定义一个字符数组,用于存储读到的字符
             * 该read(char[])返回的是读到的字符个数。
             */
            char[] buf = new char[1024];//字符数组大小为2KB
            
            int num = 0;
            while((num = fr.read(buf)) != -1) {
                System.out.println(new String(buf, 0, num));
            }
            
            fr.close();
        }
    
    }

       图示:

       练习:读取一个.java文件,并打印在控制台上。

       代码如下:

    import java.io.FileReader;
    import java.io.IOException;
    
    public class FileReaderTest {
    
        public static void main(String[] args) throws IOException {
            FileReader fr = new FileReader("FileWriterDemo2.java");
            
            char[] buf = new char[1024];
            
            int num = 0;
            
            while((num = fr.read(buf)) != -1) {
                System.out.println(new String(buf, 0, num));
            }
            
            fr.close();
        }
    
    }

       

       字符流缓冲区

       缓冲区的出现是为了提高流的操作效率而出现的,所以在创建缓冲区之前,必须要先有流对象。

       BufferedWriter

       该缓冲区中提供了一个跨平台的换行符:newLine()。

       示例代码如下:

    import java.io.BufferedWriter;
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class BufferedWriterDemo {
    
        public static void main(String[] args) throws IOException {
            /*
             * 创建一个字符写入流对象
             */
            FileWriter fw = new FileWriter("buf.txt");
            /*
             * 为了提高字符写入流的效率,加入了缓冲区。
             * 只要将需要被提高效率的流对象作为参数,传递给缓冲区的构造函数即可。
             */
            BufferedWriter bufw = new BufferedWriter(fw);
            
            for(int i = 0; i < 5; i++) {
                bufw.write("abcde" + i);
                bufw.newLine();//bufw.write("
    ")
                bufw.flush();//写一次刷新一次。
            }
            /*
             * 记住,只要用到缓冲区,就要刷新。
             */
            //bufw.flush();
            
            /*
             * 其实关闭缓冲区,就是在关闭缓冲区中的流对象。
             * 所以fw.close();就不用写了。
             */
            bufw.close();
            
            //fw.close();
        }
    
    }

       BufferedReader

       字符读取流缓冲区,该缓冲区提供了一个一次读一行的方法:readLine(),方便于对文本数据的获取。当返回null时,表示读取到文件末尾。

       readLine()方法返回的时候只返回回车符之前的数据内容,并不返回回车符(行终止符)。

       示例代码:

    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
    
    public class BufferedReaderDemo0 {
    
        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.print(line);
            }
            
            bufr.close();
        }
    
    }

       需求:明白了BufferReader类中特有方法readLine()的原理后,可以自定义一个类中包含一个功能和readLine()一致的方法,来模拟一下BufferReader。

       示例代码如下:

    import java.io.FileReader;
    import java.io.IOException;
    import java.io.Reader;
    
    class MyBufferReader extends Reader {
        /*
        private FileReader fr = null;
        
        MyBufferReader(FileReader fr) {
            this.fr = fr;
        }
        */
        
        private Reader fr = null;
        
        MyBufferReader(Reader fr) {
            this.fr = fr;
        }
        
        /*
         * 可以一次读一行数据的方法
         */
        public String myReadLine() throws IOException {
            /*
             * 定义一个临时容器,原BufferReader封装的是一个字符数组
             * 为了演示方便,定义一个StringBuilder容器,因为最终还是要将数据变为字符串。
             */
            StringBuilder sb = new StringBuilder();
            int ch = 0;
            while((ch = fr.read()) != -1) {
                if(ch == '
    ')
                    continue;
                if(ch == '
    ')
                    return sb.toString();
                else 
                    sb.append((char) ch);
            }
            if(sb.length() != 0) {//如果文本数据最后的行终止符故意去掉,那么StringBuilder里面还是有数据的 ,也要给予返回
                return sb.toString();
            }
            return null;//如果已到达流末尾,则返回 null
        }
        
        /*
         * 覆盖Reader类中的抽象方法。
         */
        @Override
        public void close() throws IOException {
            fr.close();
        }
    
        @Override
        public int read(char[] cbuf, int off, int len) throws IOException {
            return fr.read(cbuf, off, len);
        }
        
        public void myClose() throws IOException {
            fr.close();
        }
    
        
    }
    public class MyBufferReaderDemo {
    
        public static void main(String[] args) throws IOException {
            FileReader fr = new FileReader("buf.txt");
            
            MyBufferReader myBuf = new MyBufferReader(fr);
            
            String line = null;
            
            while((line = myBuf.myReadLine()) != null) {
                System.out.println(line);
            }
            
            myBuf.myClose();
        }
    
    }

       LineNumberReader

       一个带行号的缓冲区。

       示例代码如下:

    import java.io.FileReader;
    import java.io.IOException;
    import java.io.LineNumberReader;
    
    public class LineNumberReaderDemo {
    
        public static void main(String[] args) throws IOException {
            FileReader fr = new FileReader("PersonDemo.java");
            
            LineNumberReader lnr = new LineNumberReader(fr);
            
            String line = null;
            
            lnr.setLineNumber(100);//设置行号从100开始,实际打印是从101开始的
            
            while((line = lnr.readLine()) != null) {
                System.out.println(lnr.getLineNumber() + " " + line);
            }
            
            lnr.close();
        }
    
    }

       练习:模拟一个带行号的缓冲区对象。

       代码:

    import java.io.FileReader;
    import java.io.IOException;
    import java.io.Reader;
    
    class MyLineNumberReader extends MyBufferReader {
        private int lineNumber;//行号
        
        MyLineNumberReader(Reader r) {
            super(r);
        }
        
        public String myReadLine() throws IOException {
            
            lineNumber++;//myReadLine()方法读一次自增一次
            
            return super.myReadLine();
        }
    
        public int getLineNumber() {
            return lineNumber;
        }
    
        public void setLineNumber(int lineNumber) {
            this.lineNumber = lineNumber;
        }
        
    }
    /*
    class MyLineNumberReader {
        private Reader r;
        private int lineNumber;//行号
        
        MyLineNumberReader(Reader r) {
            this.r = r;
        }
        
        public String myReadLine() throws IOException {
            
            lineNumber++;//myReadLine()方法读一次自增一次
            
            StringBuilder sb = new StringBuilder();
            
            int ch = 0;
            
            while((ch = r.read()) != -1) {
                if(ch == '
    ')
                    continue;
                if(ch == '
    ') 
                    return sb.toString();
                else
                    sb.append((char) ch);
            }
            if(sb.length() != 0) {
                return sb.toString();
            }
            return null;
        }
    
        public int getLineNumber() {
            return lineNumber;
        }
    
        public void setLineNumber(int lineNumber) {
            this.lineNumber = lineNumber;
        }
        
        public void myClose() throws IOException {
            r.close();
        }
        
    }
    */
    public class MyLineNumberReaderDemo {
    
        public static void main(String[] args) throws IOException {
            FileReader fr = new FileReader("bufWriter_Copy.txt");
            
            MyLineNumberReader my = new MyLineNumberReader(fr);
            
            String line = null;
            
            //my.setLineNumber(100);
            
            while((line = my.myReadLine()) != null) {
                System.out.println(my.getLineNumber()+ " " +line);
            }
            
            my.myClose();
        }
    
    }

       由此引出装饰设计模式

       装饰设计模式:当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。那么自定义的该类称为装饰类。

       装饰类通常会通过构造方法接收被装饰的对象。并基于被装饰的对象的功能,提供更强的功能。

       举例说之:

    class Person {
        public void chifan() {
            System.out.println("吃饭");
        }
    }
    
    class SuperPerson {
        private Person p = null;
        SuperPerson(Person p) {
            this.p = p;
        }
        public void superChifan() {
            System.out.println("开胃酒");
            p.chifan();
            System.out.println("甜点");
            System.out.println("来一根");
        }
    }
    
    public class PersonDemo {
    
        public static void main(String[] args) {
            Person p = new Person();
            
            //p.chifan();
            
            SuperPerson sp = new SuperPerson(p);
            sp.superChifan();
        }
    
    }

       装饰模式与继承之间的区别

       通过以下分析:

    MyReader//专门用于读取数据的类。
        |---MyTextReader
                |---MyBufferTextReader
        |---MyMediaReader
                |---MyBufferMediaReader
        |---MyDataReader
                |---MyBufferDataReader
    
    //该类扩展性很差,找到其参数的共同类型,通过多态的形式,可以提高扩展性
    class MyBufferReader {
        
        MyBufferReader(MyTextReader text) {
        
        }
        
        MyBufferReader(MyMediaReader media) {
        
        }
    }
    ------------------------------------------------------------------
    class MyBufferReader extends MyReader {
        private MyReader r;
        MyBufferReader(MyReader r) {
            
        }
        
    }
    MyReader//专门用于读取数据的类。
        |---MyTextReader(被装饰类)
        |---MyMediaReader(被装饰类)
        |---MyDataReader(被装饰类)
        |---MyBufferReader(装饰类)

       可知:

       装饰模式比继承要灵活,避免了继承体系臃肿。而且降低了类与类之间的关系。

       装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。所以装饰类和被装饰类通常都是属于一个体系中的。

       

       练习:将c盘一个文本文件复制到d盘中。

       分析:

       复制原理:其实就是将c盘下的文件数据存储到d盘的一个文件中。

       步骤:

    1. 在d盘创建一个文件,用于存储c盘文件中的数据。
    2. 定义读取流和c盘文件关联。
    3. 通过不断的读写完成数据存储。
    4. 关闭资源。   

       代码:

    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class CoptTest {
    
        public static void main(String[] args) throws IOException {
            //copy_1();
            copy_2();
        }
        
        public static void copy_2() {
            FileWriter fw = null;
            FileReader fr = null;
            try {
                fw = new FileWriter("FileWriterDemo2_copy.java");
                fr = new FileReader("FileWriterDemo2.java");
                
                char[] buf = new char[1024];
                int len = 0;
                if((len = fr.read(buf)) != -1) {
                    fw.write(buf, 0, len);
                }
            } catch (IOException e) {
                throw new RuntimeException("读写失败");
            } finally {
                if(fr != null)
                    try {
                        fr.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                if(fw != null)
                    try {
                        fw.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
            }
        }
        /*
         * 从c盘读一个字符,就往d盘写一个字符
         */
        public static void copy_1() throws IOException {
            //创建目的地
            FileWriter fw = new FileWriter("FileWriterDemo2_copy.txt");
            
            //与已有文件关联
            FileReader fr = new FileReader("FileWriterDemo2.java");
            
            //
            int ch = 0;
            
            while((ch = fr.read()) != -1) {
                fw.write(ch);
            }
            
            fw.close();
            
            fr.close();
        }
    
    }

       用缓冲区技术优化代码:

    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class CopyTextByBuf {
    
        public static void main(String[] args) {
            BufferedReader bufr = null;
            BufferedWriter bufw = null;
            
            try {
                bufr = new BufferedReader(new FileReader("BufferedWriterDemo.java"));
                bufw = new BufferedWriter(new FileWriter("bufWriter_Copy.txt"));
                
                String line = null;
                
                while((line = bufr.readLine()) != null) {
                    bufw.write(line);
                    bufw.newLine();
                    bufw.flush();
                }
                
            } catch (IOException e) {
                throw new RuntimeException("读写失败");
            } finally {
                    try {
                        if(bufr != null)
                            bufr.close();
                    } catch (IOException e) {
                        throw new RuntimeException("读取关闭失败");
                    }
                    try {
                        if(bufw != null)
                            bufw.close();
                    } catch (IOException e) {
                        throw new RuntimeException("写入关闭失败");
                    }
            }
        }
    
    }

       图示:

  • 相关阅读:
    UIWebView stringByEvaluatingJavaScriptFromString的使用方法
    手动截图
    KVO与KVC的使用(转)
    LKDBHelper Sqlite操作数据库
    GCD多线程的使用
    ios --- 调用系统"设置"里的功能(转)
    ios开发小技巧(转)
    url字符串中含中文的转码方法
    ios 照片编辑的view封装
    字符串去空格
  • 原文地址:https://www.cnblogs.com/yerenyuan/p/5267278.html
Copyright © 2020-2023  润新知