• 08


    IO流

    JAVA流式输入输出原理:可以想象成一根管道怼到文件上,另一端是我们程序,然后流的输入输出都是按照程序本身作为第一人称说明的。比如 input,对于我们程序来说就是有数据输入我们程序,output就是我们程序输出数据到文件等。对象不能搞错了,否则就南辕北辙了。

    • 通过不同的角度对流的输入输出功能进行分类:
    1. 按数据流的方向分为:输入流和输出流
    2. 按处理数据单位不同分为:字节流和字符流(2个字节)
    3. 按功能不同分为:节点流和处理流

    输入流和输出流

    • JAVA JDK 所提供的所有流类型位于包 java.io 内部,分别继承自下面四个抽象流类型:

      	字节流         	字符流   
      

      输入流 InputStream Reader
      输出流 OutputStream Writer


    节点流和处理流

    • 节点流为可以从一个特定的数据源(节点)读写数据(如:文件,内存)。

    节点流可以简单的理解为:一根管道直接怼到文件上,进行数据的读写。

    • 处理流是连接在已存在的节点流或处理流上的,通过读数据进行处理(过滤等)为程序提供更加强大的读写功能。

    处理流可以简单的理解为:套在节点流管道的管子,可以对流过节点流的数据进行处理,过滤等操作。


    InputStream 抽象类

    • 继承自 InputStream的流都是用于向程序中输入数据,且数据的单位为字节。
    • 继承自 InputStream的类有如下等:(加粗为节点流,未加粗为处理流)

    FileInputStream

    PipedInputStream

    FilterInputStream

    ByteArrayInputStream

    SequenceInputStream

    StringBufferInputStream

    ObjectInputStream

    • InputStream的基本方法

      int read() throws IOException
      int read(byte[] buffer) throws IOException
      int read(byte[] buffer, int offset, int length) throws IOException
      void close() throws IOException


    OutputStream 抽象类

    • 继承自 OutputStream的流都是用于从程序中输出数据,且数据的单位为字节。
    • 继承自 OutputStream的类有如下等:(加粗为节点流,未加粗为处理流)

    FileOutputStream

    PipedOutputStream

    FilterOutputStream

    ByteArrayOutputStream

    ObjectOutputStream

    • OutputStream 基本方法

      void write(int b) throws IOException
      void write(byte[] b) throws IOException
      void write(byte[] b, int off, int len) throws IOException
      void close() throws IOException
      void flush() throws IOException // 在关闭输出流之前使用,将输出缓冲区的数据写到目的地


    Reader

    • 继承自 Reader 的流都是用于程序从外部读入数据,且数据的单位是字符(2个字节)。
    • 如下为继承自Reader的流。(加粗为节点流,未加粗为处理流)

    BufferedReader

    CharArrayReader

    InputStreamReader

    FilterReader

    PipedReader

    StringReader

    • Reader的基本方法 - 略

    Writer

    • 继承自 Writer的流都是用于程序向外部写入数据,且数据的单位是字符(2个字节)。
    • 如下为继承自Writer的流。(加粗为节点流,未加粗为处理流)

    BufferedWriter

    CharArrayWriter

    OutputStreamWriter

    FilterWriter

    PipedWriter

    StringWriter

    • Writer的基本方法 - 略

    节点流类型

    类型 字节流 字符流
    File(文件) FileInputStream / FileOutputStream FileReader / FileWriter
    Memory Array ByteArrayInputStream / ByteArrayOutputStream CharArrayReader / CharArrayWriter
    Memory String -- StringReader / StringWriter
    Pipe(管道) PipedInputStream / PipedOutputStream PipedReader / PipedWriter

    举例1:FileInputStream

    import java.io.*;
    public class Test {
        public static void main(String[] args) {
            int b = 0;
            long num = 0;
            FileInputStream ln = null;
    
            try {
                 ln = new FileInputStream("I:/Java/Demo/test.txt");
            } catch (FileNotFoundException e) {
                System.out.println("文件不存在!");
                System.exit(-1);
            }
    
            try {
                while ((b=ln.read()) != -1) {
                    System.out.print((char)b);
                    num++;
                }
                ln.close();
                System.out.println();
                System.out.println("共读出:" + num + "个字节。");
            } catch (IOException e) {
                System.out.println("文件读取失败!");
                System.exit(-1);
            }
        }
    }
    

    举例2:FileOutputStream

    import java.io.*;
    public class Test {
        public static void main(String[] args) {
            int b = 0;
            FileInputStream in = null;
            FileOutputStream out = null;
    
            try {
                in = new FileInputStream("I:/Java/Demo/test.txt");
                out = new FileOutputStream("I:/Java/Demo/newtest.txt");
    
                while((b=in.read()) != -1) {
                    out.write(b);
                }
            } catch (FileNotFoundException e) {
                System.out.println("文件不存在!");
                System.exit(-1);
    
            } catch (IOException e) {
                System.out.println("文件复制失败!");
                System.exit(-2);
            }
            System.out.println("文件复制成功!");
        }
    }
    

    处理流类型

    处理类型 字节流 字符流
    Buffering BufferedInputStream/BufferedOutputStream BufferedReader/BufferedWriter
    Filtering FilterInputStream/FilterOutputStream FilterReader/FilterWriter
    Converting between bytes and character -- InputStreamReader/OutputStreamWriter
    Object Serialization ObjectInputStream/ObjectOutputStream --
    Data conversion DataInputStream/DataOutputStream --
    Counting LineNumberInputStream LineNumberReader
    Peeking ahead PushbackInputStream PushbackReader
    Printing PrintStream PrintWriter

    • 缓冲流(以Buffered开头)
    1. 缓冲流套接在相应的节点流上,对读写的数据提供了缓冲的功能,提高了读写的效率,同时增加了一些新的方法。

      BufferedReader / BufferedWriter / BufferedInputStream / BufferedOutputStream

    2. 缓冲流支持其父类的 mark 和 reset 方法。

    3. BufferedReader 提供了 readLine 方法用于读取一行字符串(以 或者 分割)

    4. BufferedWriter 提供了 newLine 用于写入一个行分隔符。

    5. 对于输出的缓冲流,写出的数据会先在内存中缓存,使用 flush 方法将会使内存中的数据立刻写出。

    举例1:

    import java.io.*;
    public class Test {
        public static void main(String[] args) {
            int b = 0;
            FileInputStream in = null;
            BufferedInputStream bin = null;
    
            try {
                in = new FileInputStream("I:/Java/Demo/test.txt");
                bin = new BufferedInputStream(in);
    
                bin.mark(100);
    
                for(int i=0; (i<=10)&&(b=bin.read()) != -1; i++) {
                    System.out.print((char)b);
                }
    
                bin.reset();
                System.out.println();
    
                for(int i=0; (i<=10)&&(b=bin.read()) != -1; i++) {
                    System.out.print((char)b);
                }
    
            } catch (FileNotFoundException e) {
                System.out.println("文件不存在!");
                System.exit(-1);
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    举例2:

    import java.io.*;
    public class Test {
        public static void main(String[] args) {
            String s = null;
            try {
                BufferedWriter bw = new BufferedWriter(new FileWriter("I:/Java/Demo/test.txt"));
                BufferedReader br = new BufferedReader(new FileReader("I:/Java/Demo/test.txt"));
    
                for(int i=0; i<100; i++) {
                    s = Double.toString(Math.random());
                    bw.write(s);
                    bw.newLine();
                }
    
                bw.flush();
    
                while((s=br.readLine()) != null) {
                    System.out.println(s);
                }
    
                bw.close();
                br.close();
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //0.7365309652822098
    //0.577186775602007
    //0.11736466966949166
    //0.2998096440959087
    //0.23859539950503672
    //...
    
    • 转换流
    1. InputStreamReader 和 OutputStreamWriter 用于字节数据到字符数据之间的转换。
    2. InputStreamReader 需要和 InputStream 套接。
    3. OutputStreamWriter 需要和 OutputStream 套接。
    4. 转换流在构造时可以指定其编码结合,例如: InputStream is = new InputStreamReader(System.in, "ISO8859_1")

    举例1:

    import java.io.*;
    public class Test {
        public static void main(String[] args) {
            try {
                OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("I:/Java/Demo/test.txt"));
                osw.write("1234567890");
                System.out.println(osw.getEncoding());
                osw.flush();
                osw.close();
    
                osw = new OutputStreamWriter(new FileOutputStream("I:/Java/Demo/test.txt", true), "ISO8859_1");
                osw.write("abcdefghijklmn");
                System.out.println(osw.getEncoding());
                osw.flush();
                osw.close();
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    举例2:

    import java.io.*;
    public class Test {
        public static void main(String[] args) {
            try {
                String s = null;
                InputStreamReader isr = new InputStreamReader(System.in);
                BufferedReader br = new BufferedReader(isr);
    
                while((s = br.readLine()) != null) {
                    if(s.equalsIgnoreCase("exit")) {
                        break;
                    }
                    System.out.println(s);
                }
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    • 数据流
    1. DataInputStream 和 DataOutputStream 分别继承自 InputStream 和 OutputStream,它属于处理流,需要分别套接在 InputStream 和 OutputStream 类型的节点流上。
    2. DataInputStream 和 DataOutputStream 提供了可以存取与机器无关的 Java 原始类型数据(如:int,double 等)的方法。
    3. DataInputStream 和 DataOutputStream 的构造方法为:
      DataInputStream (InputStream in)
      DataOutputStream (OutputStream out)

    数据流的作用?

    比如,我们如何存储一个很大的数到文件?我们之前的方法是将其转换成字符串存储,可不可以直接存储呢?数据流可以。它提供了很多方法用于存储基础数据类型的数据,参看 API 文档。

    举例1:

    import java.io.*;
    public class Test {
        public static void main(String[] args) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 在内存自动生成一个 Byte[] 数组
            DataOutputStream dos = new DataOutputStream(baos);
    
            try {
                dos.writeDouble(Math.random());
                dos.writeBoolean(true);
    
                ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
                System.out.println(bais.available());
    
                DataInputStream dis = new DataInputStream(bais);
    
                System.out.println(dis.readDouble());
                System.out.println(dis.readBoolean());
    
                dos.close();
                dis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    问题:我们写一个 double,写一个boolean写到哪里了呢?

    其实,在我们 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 的时候,就在内存中开辟了一块空间,用来将程序要写入的数据写到这片内存中。

    还有,在读数据的时候,由于这片内存的分配是按照队列的方式分配的,所以先写进去的数据要先读出来,如果如上面程序那样,先读boolean的话,就会读取到double 8个字节的第一个字节上,切记!

    • Print 流(打印流)
    1. PrintWriter 和 PrintStream 都属于输出流,分别针对与字符和字节。

    2. PrintWriter 和 PrintStream 提供了重载的 print println 方法用于多种数据类型的输出。

    3. PrintWriter 和 PrintStream 的输出操作不会抛出异常,用户通过检测错误状态获取错误信息。

    4. PrintWriter 和 PrintStream 有自动 flush 功能。

      PrintWriter(PrintWriter out)
      PrintWriter(Writer out, boolean autoFlush)
      PrintWriter(OutputStream out)
      PrintWriter(OutputStream out, boolean autoFlush)
      PrintStream(OutputStream out)
      PrintStream(OutputStream out, boolean autoFlush)

    举例1:

    import java.io.*;
    public class Test {
        public static void main(String[] args) {
            PrintStream ps = null;
    
            try {
                FileOutputStream fos = new FileOutputStream("I:\Java\Demo\test.txt");
    
                ps = new PrintStream(fos);
    
                if(null != ps) {
                    System.setOut(ps);
                }
    
                for(int i=0; i<60000; i++) {
                    System.out.print((char)i + " ");
    
                    if(i%50 == 0) {
                        System.out.println();
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    将输出打印语句重定向到 test.txt 文件中。

    举例2:

    import java.io.*;
    
    public class Test {
        public static void main(String[] args) {
            String filename = args[0];
    
            if (filename != null) {
                list(filename, System.out);
            }
        }
    
        public static void list(String f, PrintStream fs) {
            try {
                String s = null;
                BufferedReader br = new BufferedReader(new FileReader(f));
    
                while ((s = br.readLine()) != null) {
                    fs.println(s);
                }
                br.close();
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    将 args[0] 所写的文件名对应的文件打印到终端。

    举例3:

    import java.io.*;
    import java.util.*;
    
    public class Test {
        public static void main(String[] args) {
            String s = null;
    
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    
            try {
                FileWriter fw = new FileWriter("I:/Java/Demo/log.txt", true);
                PrintWriter log = new PrintWriter(fw);
    
                while((s=br.readLine()) != null) {
                    if(s.equalsIgnoreCase("exit")) {
                        break;
                    }
                    System.out.println(s);
                    log.println("------");
                    log.println(s);
                    log.flush(); // 可以省略
    
                }
                log.println("--- " + new Date() + " ---");
                log.flush(); // 可以省略
                log.close();
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    将从终端输入的内容作为 log 写到 log.txt 文件里面。

    • Object 流

    Object 流的作用:当我们存储一个元素的时候,(比如在画图软件上画了一个圆)我们的圆有很多属性,原点位置,半径大小,颜色,粗细等,既然每一个属性都需要存储,而且这些属性都在一个 Object 对象里面,那么我们为什么不直接写整个 Object呢?(这叫序列化。)

    注意:当你 new 一个 Object 的时候,不单单只有你的属性,还有一些比如 Object的版本号,this,super 等。

    举例:

    import java.io.*;
    public class Test {
        public static void main(String[] args) {
            TmpClass tm = new TmpClass();
            tm.a  =10;
            tm.d = false;
    
            try {
                FileOutputStream fos = new FileOutputStream("I:/Java/Demo/text.txt");
                ObjectOutputStream oos = new ObjectOutputStream(fos);
    
                oos.writeObject(tm);
                oos.flush();
                oos.close();
    
                FileInputStream fis = new FileInputStream("I:/Java/Demo/text.txt");
                ObjectInputStream ois = new ObjectInputStream(fis);
                TmpClass t = (TmpClass) ois.readObject();
                System.out.println(t.a + " " + t.b + " " + t.c + " " + t.d);
            } catch (ClassNotFoundException c) {
                System.out.println("读取文件失败");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    class TmpClass implements Serializable {
        int a = 1;
        int b = 2;
        double c = 3.0;
        boolean d = true;
    }
    
    • Serializable 接口
    1. 可以被序列化的,如果想把一个类的对象,写到硬盘或者网络,想把这个对象序列化成一个字节流的话,必须要实现这个接口。
    2. 这个接口没有任何方法,是一个空接口,是一个标记性接口,它只是给编译器看的,编译器看到后就知道这个类的对象时可以被序列化的,是可以整个写入文件的。
    • tansient关键字
    1. 使用方法,修饰成员变量。

      class TmpClass implements Serializable {
          int a = 1;
          int b = 2;
          tansient double c = 3.0;
          boolean d = true;
      }
      
    2. transient 表示透明的意思,就是说在一个类的对象序列化的时候不予考虑,就是将这个类的对象写入文件的时候,不写这个被transient 修饰的成员变量,那么我们再读出来的时候就是默认值(如上,c 读出来的时候是 0.0)

    • externalizable 接口
    1. 可以理解为个性化的 Serializable 接口,externalizable 接口是继承 Serializable 接口得到的,相当于自己控制序列化的过程。(了解就好)

    总结

    • 本章复习方法:把所有的名字,关键字写到一张纸上,每天看看想想自己,给朕看半个时辰。—— 康熙
  • 相关阅读:
    随笔——关于读论文
    enumerate
    torch.max
    C# WPF侧边栏导航菜单(Dropdown Menu)
    C# WPF过渡效果实现(C# WPF Material Design UI: Transitions)
    用C# WPF简单实现仪表控件
    自定义滚动条(Custom ScrollBar)
    从头实现一个WPF条形图
    漂亮的无序列表样式
    C# WPF实用的注册窗体
  • 原文地址:https://www.cnblogs.com/lvonve/p/8323649.html
Copyright © 2020-2023  润新知