美文网首页
Java编程思想(十七) Java I/O系统

Java编程思想(十七) Java I/O系统

作者: kaiker | 来源:发表于2022-07-02 14:38 被阅读0次

    1、File类

    • 既能代表一个特定文件的名称,又能代表一个目录下的一组文件名称。
    • 如果它值得是一个文件集,可以对此集合调用list()方法,这个方法会返回一个字符数组。

    目录列举器

    public class DirList3 {
      public static void main(final String[] args) {
        File path = new File(".");
        String[] list;
        if(args.length == 0)
          list = path.list();
        else
          list = path.list(new FilenameFilter() {
            private Pattern pattern = Pattern.compile(args[0]);
            public boolean accept(File dir, String name) {
              return pattern.matcher(name).matches();
            }
          });
        Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
        for(String dirItem : list)
          System.out.println(dirItem);
      }
    } /* Output:
    DirectoryDemo.java
    DirList.java
    DirList2.java
    DirList3.java
    *///:~
    

    目录实用工具

    • local()方法使用被称为listFile()的File.list()的变体来产生File数组。
    • walk()方法将开始目录的名字转换为File对象,然后调用recurseDirs(),将该方法递归地遍历目录。

    2、输入和输出

    • 流,代表任何有能力产出数据的数据源对象或者是有能力接收数据的接收端对象。屏蔽了实际的IO设备中处理数据的细节。
    • IO类分为输出和输入两部分。InputStream或Reader派生而来的类都含有名为read()的基本方法,OutputStream或Writer派生而来的类都还有名为write()的基本方法。

    InputStream类型

    • 表示哪些从不同数据源产生输入的类。
    • 数据源包括:字节数组、String对象、文件、管道、一个由其他种类的流组成的序列、其他数据源。
    InputStream类型

    OutputStream类型

    • 决定了输出所要去往的目标:字节数组、文件或管道。
    OutputStream类型

    3、添加属性和有用的接口

    • IO这块大量运用了装饰器模式。
    • FilterInputStream和FilterOutputStream是用来提供装饰器类接口以控制特定输入流和输出流的两个类。
    • DataInputStream允许我们读取不同基本类型数据以及String对象。
    • 其他FilterInputStream类则在内部修改InputStream的行为方式。
    FilterInputStream FilterOutputStream

    4、Reader和Writer

    • 设计Reader和Writer继承层次结构主要为了国际化,可以处理16位Unicode字符。
    • 无论何时使用readLine()都不应该使用DataInputStream,而应该使用使用BufferedReader。
    对比

    5、RandomAccessFile

    • 用于由一只大小的记录组成的文件。可以使用seek()将记录从一处转移到另一处,然后读取或修改记录。

    6、IO流的典型使用方式

    缓冲输入文件

    public class BufferedInputFile {
      // Throw exceptions to console:
      public static String
      read(String filename) throws IOException {
        // Reading input by lines:
        BufferedReader in = new BufferedReader(
          new FileReader(filename));
        String s;
        StringBuilder sb = new StringBuilder();
        while((s = in.readLine())!= null)
          sb.append(s + "\n");
        in.close();
        return sb.toString();
      }
      public static void main(String[] args)
      throws IOException {
        System.out.print(read("BufferedInputFile.java"));
      }
    } /* (Execute to see output) *///:~
    

    从内存输入

    public class MemoryInput {
      public static void main(String[] args)
      throws IOException {
        StringReader in = new StringReader(
          BufferedInputFile.read("MemoryInput.java"));
        int c;
        while((c = in.read()) != -1)
          System.out.print((char)c);
      }
    } /* (Execute to see output) *///:~
    

    格式化内存输入

    • DataInputStream是一个面向字节的IO类,不是面向字符的。
    public class FormattedMemoryInput {
      public static void main(String[] args)
      throws IOException {
        try {
          DataInputStream in = new DataInputStream(
            new ByteArrayInputStream(
             BufferedInputFile.read(
              "FormattedMemoryInput.java").getBytes()));
          while(true)
            System.out.print((char)in.readByte());
        } catch(EOFException e) {
          System.err.println("End of stream");
        }
      }
    } /* (Execute to see output) *///:~
    

    文件输出

    public class BasicFileOutput {
      static String file = "BasicFileOutput.out";
      public static void main(String[] args)
      throws IOException {
        BufferedReader in = new BufferedReader(
          new StringReader(
            BufferedInputFile.read("BasicFileOutput.java")));
        PrintWriter out = new PrintWriter(
          new BufferedWriter(new FileWriter(file)));
        int lineCount = 1;
        String s;
        while((s = in.readLine()) != null )
          out.println(lineCount++ + ": " + s);
        out.close();
        // Show the stored file:
        System.out.println(BufferedInputFile.read(file));
      }
    } /* (Execute to see output) *///:~
    
    

    7、标准IO

    • 程序的所有输入都可以来自于标准输入,它的所有输出也都可以发送到标准输出,以及所有的错误信息都可以发送到标准错误。
    • System.out System.In System.err是标准IO模型构建。
    public class Echo {
      public static void main(String[] args)
      throws IOException {
        BufferedReader stdin = new BufferedReader(
          new InputStreamReader(System.in));
        String s;
        while((s = stdin.readLine()) != null && s.length()!= 0)
          System.out.println(s);
        // An empty line or Ctrl-Z terminates the program
      }
    } ///:~
    
    • 对标准输入、输出和错误IO流进行重定向。
    public class Redirecting {
      public static void main(String[] args)
      throws IOException {
        PrintStream console = System.out;
        BufferedInputStream in = new BufferedInputStream(
          new FileInputStream("Redirecting.java"));
        PrintStream out = new PrintStream(
          new BufferedOutputStream(
            new FileOutputStream("test.out")));
        System.setIn(in);
        System.setOut(out);
        System.setErr(out);
        BufferedReader br = new BufferedReader(
          new InputStreamReader(System.in));
        String s;
        while((s = br.readLine()) != null)
          System.out.println(s);
        out.close(); // Remember this!
        System.setOut(console);
      }
    } ///:~
    

    8、新IO

    • 通道和缓冲器。可以可以把它想象成一个煤矿,通道是一个包含数据的矿藏,而缓冲器则是派送到矿藏的卡车。我们从卡车上获取矿藏。我们没有直接和通道交互,只是和缓冲器交互。
    • 唯一直接与通道交互的缓冲器是ByteBuffer。
    public class GetChannel {
      private static final int BSIZE = 1024;
      public static void main(String[] args) throws Exception {
        // Write a file:
        FileChannel fc =
          new FileOutputStream("data.txt").getChannel();
        fc.write(ByteBuffer.wrap("Some text ".getBytes()));public class Redirecting {
      public static void main(String[] args)
      throws IOException {
        PrintStream console = System.out;
        BufferedInputStream in = new BufferedInputStream(
          new FileInputStream("Redirecting.java"));
        PrintStream out = new PrintStream(
          new BufferedOutputStream(
            new FileOutputStream("test.out")));
        System.setIn(in);
        System.setOut(out);
        System.setErr(out);
        BufferedReader br = new BufferedReader(
          new InputStreamReader(System.in));
        String s;
        while((s = br.readLine()) != null)
          System.out.println(s);
        out.close(); // Remember this!
        System.setOut(console);
      }
    } ///:~
        fc.close();
        // Add to the end of the file:
        fc =
          new RandomAccessFile("data.txt", "rw").getChannel();
        fc.position(fc.size()); // Move to the end
        fc.write(ByteBuffer.wrap("Some more".getBytes()));
        fc.close();
        // Read the file:
        fc = new FileInputStream("data.txt").getChannel();
        ByteBuffer buff = ByteBuffer.allocate(BSIZE);
        fc.read(buff);
        buff.flip();
        while(buff.hasRemaining())
          System.out.print((char)buff.get());
      }
    } /* Output:
    Some text Some more
    *///:~
    
    • 通道是一种相当基础的东西,可以向它传送用于读写的ByteBuffer。
    • 将字节存放于ByteBuffer的方法之一是使用一种put方法进行填充,也可以使用warp()方法将已存在的字节数组保障到ByteBuffer中。
    public class ChannelCopy {
      private static final int BSIZE = 1024;
      public static void main(String[] args) throws Exception {
        if(args.length != 2) {
          System.out.println("arguments: sourcefile destfile");
          System.exit(1);
        }
        FileChannel
          in = new FileInputStream(args[0]).getChannel(),
          out = new FileOutputStream(args[1]).getChannel();
        ByteBuffer buffer = ByteBuffer.allocate(BSIZE);
        while(in.read(buffer) != -1) {
          buffer.flip(); // Prepare for writing
          out.write(buffer);
          buffer.clear();  // Prepare for reading
        }
      }
    } ///:~
    

    获取基本类型

    public class GetData {
      private static final int BSIZE = 1024;
      public static void main(String[] args) {
        ByteBuffer bb = ByteBuffer.allocate(BSIZE);
        // Allocation automatically zeroes the ByteBuffer:
        int i = 0;
        while(i++ < bb.limit())
          if(bb.get() != 0)
            print("nonzero");
        print("i = " + i);
        bb.rewind();
        // Store and read a char array:
        bb.asCharBuffer().put("Howdy!");
        char c;
        while((c = bb.getChar()) != 0)
          printnb(c + " ");
        print();
        bb.rewind();
        // Store and read a short:
        bb.asShortBuffer().put((short)471142);
        print(bb.getShort());
        bb.rewind();
        // Store and read an int:
        bb.asIntBuffer().put(99471142);
        print(bb.getInt());
        bb.rewind();
        // Store and read a long:
        bb.asLongBuffer().put(99471142);
        print(bb.getLong());
        bb.rewind();
        // Store and read a float:
        bb.asFloatBuffer().put(99471142);
        print(bb.getFloat());
        bb.rewind();
        // Store and read a double:
        bb.asDoubleBuffer().put(99471142);
        print(bb.getDouble());
        bb.rewind();
      }
    } /* Output:
    i = 1025
    H o w d y !
    12390
    99471142
    99471142
    9.9471144E7
    9.9471142E7
    *///:~
    
    • 视图缓冲器可以让我们通过某个特定的基本数据类型的视窗查看其底层ByteBuffer
    • ByteBuffer通过一个被包装过的8字节数组产生,然后通过各种不同的基本类型的视图缓冲器显示出来
    public class IntBufferDemo {
      private static final int BSIZE = 1024;
      public static void main(String[] args) {
        ByteBuffer bb = ByteBuffer.allocate(BSIZE);
        IntBuffer ib = bb.asIntBuffer();
        // Store an array of int:
        ib.put(new int[]{ 11, 42, 47, 99, 143, 811, 1016 });
        // Absolute location read and write:
        System.out.println(ib.get(3));
        ib.put(3, 1811);
        // Setting a new limit before rewinding the buffer.
        ib.flip();
        while(ib.hasRemaining()) {
          int i = ib.get();
          System.out.println(i);
        }
      }
    } /* Output:
    99
    11
    42
    47
    1811
    143
    811
    1016
    *///:~
    
    bytebuffer包装

    缓冲器的细节

    • Buffer由数据和可以高效访问及操纵这些数据的四个索引组成,mark标记,position位置,limit界限和capacity容量。


      索引方法
      索引示例

    文件加锁。

    • 文件锁对其他的操作系统进程是可见的。
    public class FileLocking {
      public static void main(String[] args) throws Exception {
        FileOutputStream fos= new FileOutputStream("file.txt");
        FileLock fl = fos.getChannel().tryLock();
        if(fl != null) {
          System.out.println("Locked File");
          TimeUnit.MILLISECONDS.sleep(100);
          fl.release();
          System.out.println("Released Lock");
        }
        fos.close();
      }
    } /* Output:
    Locked File
    Released Lock
    *///:~
    

    9、压缩

    压缩类

    10、对象序列化

    • Java的对象序列化将那些实现了Serializable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象。
    • 持久性意味着一个对象的生命周期并不取决于程序是否正在执行,它可以生存于程序的调用之间。通过将一个序列化对象写入磁盘,然后在重新调用程序时回复该对象,就能够实现持久性效果。
    • 称为轻量级是因为不能通过关键字来简单定义一个对象,并让系统自动维护其他细节问题,对象必须在程序中显示地序列化和反序列化还原。
    • 只要实现了Serializable接口。
    • 要序列化一个对象,首先要创建某些outputStream对象,然后将其封装在一个ObjectOutputStream对象内。只需调用writeObject即可将对象序列化。
    • 将一个InputStream封装在ObjectInputStream内,然后调用readObject。
    class Data implements Serializable {
      private int n;
      public Data(int n) { this.n = n; }
      public String toString() { return Integer.toString(n); }
    }
    
    public class Worm implements Serializable {
      private static Random rand = new Random(47);
      private Data[] d = {
        new Data(rand.nextInt(10)),
        new Data(rand.nextInt(10)),
        new Data(rand.nextInt(10))
      };
      private Worm next;
      private char c;
      // Value of i == number of segments
      public Worm(int i, char x) {
        print("Worm constructor: " + i);
        c = x;
        if(--i > 0)
          next = new Worm(i, (char)(x + 1));
      }
      public Worm() {
        print("Default constructor");
      }
      public String toString() {
        StringBuilder result = new StringBuilder(":");
        result.append(c);
        result.append("(");
        for(Data dat : d)
          result.append(dat);
        result.append(")");
        if(next != null)
          result.append(next);
        return result.toString();
      }
      public static void main(String[] args)
      throws ClassNotFoundException, IOException {
        Worm w = new Worm(6, 'a');
        print("w = " + w);
        ObjectOutputStream out = new ObjectOutputStream(
          new FileOutputStream("worm.out"));
        out.writeObject("Worm storage\n");
        out.writeObject(w);
        out.close(); // Also flushes output
        ObjectInputStream in = new ObjectInputStream(
          new FileInputStream("worm.out"));
        String s = (String)in.readObject();
        Worm w2 = (Worm)in.readObject();
        print(s + "w2 = " + w2);
        ByteArrayOutputStream bout =
          new ByteArrayOutputStream();
        ObjectOutputStream out2 = new ObjectOutputStream(bout);
        out2.writeObject("Worm storage\n");
        out2.writeObject(w);
        out2.flush();
        ObjectInputStream in2 = new ObjectInputStream(
          new ByteArrayInputStream(bout.toByteArray()));
        s = (String)in2.readObject();
        Worm w3 = (Worm)in2.readObject();
        print(s + "w3 = " + w3);
      }
    } /* Output:
    Worm constructor: 6
    Worm constructor: 5
    Worm constructor: 4
    Worm constructor: 3
    Worm constructor: 2
    Worm constructor: 1
    w = :a(853):b(119):c(802):d(788):e(199):f(881)
    Worm storage
    w2 = :a(853):b(119):c(802):d(788):e(199):f(881)
    Worm storage
    w3 = :a(853):b(119):c(802):d(788):e(199):f(881)
    *///:~
    

    寻找类

    • 将一个对象从它的序列化状态中恢复,哪些工作是必须的。
    • 必须保证Java虚拟机能够找到相关的.class文件

    部分序列化

    • Externalizable接口,有writeexternal()和readExternal()这两个方法会在序列化和反序列化还原过程中
    • Serializable对象完全以它存储的二进制位为基础来构造,而不调用构造器。
    • Externalizable所有默认构造器都会被调用。
    public class Blip3 implements Externalizable {
      private int i;
      private String s; // No initialization
      public Blip3() {
        print("Blip3 Constructor");
        // s, i not initialized
      }
      public Blip3(String x, int a) {
        print("Blip3(String x, int a)");
        s = x;
        i = a;
        // s & i initialized only in non-default constructor.
      }
      public String toString() { return s + i; }
      public void writeExternal(ObjectOutput out)
      throws IOException {
        print("Blip3.writeExternal");
        // You must do this:
        out.writeObject(s);
        out.writeInt(i);
      }
      public void readExternal(ObjectInput in)
      throws IOException, ClassNotFoundException {
        print("Blip3.readExternal");
        // You must do this:
        s = (String)in.readObject();
        i = in.readInt();
      }
      public static void main(String[] args)
      throws IOException, ClassNotFoundException {
        print("Constructing objects:");
        Blip3 b3 = new Blip3("A String ", 47);
        print(b3);
        ObjectOutputStream o = new ObjectOutputStream(
          new FileOutputStream("Blip3.out"));
        print("Saving object:");
        o.writeObject(b3);
        o.close();
        // Now get it back:
        ObjectInputStream in = new ObjectInputStream(
          new FileInputStream("Blip3.out"));
        print("Recovering b3:");
        b3 = (Blip3)in.readObject();
        print(b3);
      }
    } /* Output:
    Constructing objects:
    Blip3(String x, int a)
    A String 47
    Saving object:
    Blip3.writeExternal
    Recovering b3:
    Blip3 Constructor
    Blip3.readExternal
    A String 47
    *///:~
    
    • 可以使用transient关键字,逐个字段关闭序列化。
    public class Logon implements Serializable {
      private Date date = new Date();
      private String username;
      private transient String password;
      public Logon(String name, String pwd) {
        username = name;
        password = pwd;
      }
      public String toString() {
        return "logon info: \n   username: " + username +
          "\n   date: " + date + "\n   password: " + password;
      }
      public static void main(String[] args) throws Exception {
        Logon a = new Logon("Hulk", "myLittlePony");
        print("logon a = " + a);
        ObjectOutputStream o = new ObjectOutputStream(
          new FileOutputStream("Logon.out"));
        o.writeObject(a);
        o.close();
        TimeUnit.SECONDS.sleep(1); // Delay
        // Now get them back:
        ObjectInputStream in = new ObjectInputStream(
          new FileInputStream("Logon.out"));
        print("Recovering object at " + new Date());
        a = (Logon)in.readObject();
        print("logon a = " + a);
      }
    } /* Output: (Sample)
    logon a = logon info:
       username: Hulk
       date: Sat Nov 19 15:03:26 MST 2005
       password: myLittlePony
    Recovering object at Sat Nov 19 15:03:28 MST 2005
    logon a = logon info:
       username: Hulk
       date: Sat Nov 19 15:03:26 MST 2005
       password: null
    *///:~
    

    使用持久性

    • 可以通过一个字节数组来使用对象序列化,从而实现对任何可Serializable对象的深度复制。
    public class MyWorld {
      public static void main(String[] args)
      throws IOException, ClassNotFoundException {
        House house = new House();
        List<Animal> animals = new ArrayList<Animal>();
        animals.add(new Animal("Bosco the dog", house));
        animals.add(new Animal("Ralph the hamster", house));
        animals.add(new Animal("Molly the cat", house));
        print("animals: " + animals);
        ByteArrayOutputStream buf1 =
          new ByteArrayOutputStream();
        ObjectOutputStream o1 = new ObjectOutputStream(buf1);
        o1.writeObject(animals);
        o1.writeObject(animals); // Write a 2nd set
        // Write to a different stream:
        ByteArrayOutputStream buf2 =
          new ByteArrayOutputStream();
        ObjectOutputStream o2 = new ObjectOutputStream(buf2);
        o2.writeObject(animals);
        // Now get them back:
        ObjectInputStream in1 = new ObjectInputStream(
          new ByteArrayInputStream(buf1.toByteArray()));
        ObjectInputStream in2 = new ObjectInputStream(
          new ByteArrayInputStream(buf2.toByteArray()));
        List
          animals1 = (List)in1.readObject(),
          animals2 = (List)in1.readObject(),
          animals3 = (List)in2.readObject();
        print("animals1: " + animals1);
        print("animals2: " + animals2);
        print("animals3: " + animals3);
      }
    } /* Output: (Sample)
    animals: [Bosco the dog[Animal@addbf1], House@42e816
    , Ralph the hamster[Animal@9304b1], House@42e816
    , Molly the cat[Animal@190d11], House@42e816
    ]
    animals1: [Bosco the dog[Animal@de6f34], House@156ee8e
    , Ralph the hamster[Animal@47b480], House@156ee8e
    , Molly the cat[Animal@19b49e6], House@156ee8e
    ]
    animals2: [Bosco the dog[Animal@de6f34], House@156ee8e
    , Ralph the hamster[Animal@47b480], House@156ee8e
    , Molly the cat[Animal@19b49e6], House@156ee8e
    ]
    animals3: [Bosco the dog[Animal@10d448], House@e0e1c6
    , Ralph the hamster[Animal@6ca1c], House@e0e1c6
    , Molly the cat[Animal@1bf216a], House@e0e1c6
    ]
    *///:~
    
    • Class是Serializable的,因此只需直接对Class对象序列化,就可以很容易地保存static字段。
    • 如果想序列化static值,必须自己手动实现

    相关文章

      网友评论

          本文标题:Java编程思想(十七) Java I/O系统

          本文链接:https://www.haomeiwen.com/subject/vvdgvrtx.html