20210327JavaIO流

JavaIO流

编辑时间:2021/03/27

读完本节:大概花费20钟,共3275词

1.对象流
  1. ObjectInputStream和ObjectOutputStream

    1. 用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来
  2. 序列化:用ObjectOutputStream类保存基本数据类型数据或对象的机制

  3. 反序列化:用ObjectInputStream类读取基本数据类型数据或对象的机制

  4. ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量,原因是static修饰的类和变量是共享的在对象实例化之前;transient一旦修饰某个变量,则表示这个变量不再是对象持久化的一部分,该变量内容在序列化后无法获得访问,transient关键字只能修饰变量,不能修饰方法和类,同时本地变量不能被transient修饰,变量如果是用户自定义类的变量,则该类需要实现Serializable接口

  5. 对象的序列化机制:该机制允许内存中的Java对象转换成与平台无关的二进制流,从而允许把这种二进制流持久的保存在硬盘上,或通过网络将这种二进制流传输到另一个网络节点。当其他程序获取了这中二进制流,就可以恢复成原来内存中的Java对象

  6. 序列化的好处在于可以将任何实现了Serializable接口的对象转化为字节数据,使其在保存和传输时可以被还原

  7. 序列化时**RMI(Remote Method Invoke - 远程方法调用)**过程的参数和返回值都必须实现的机制,而RMI是JavaEE的基础。因此序列化机制是JavaEE平台的基础

  8. 如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可序列化的,为了让某个类是可序列化的,该类必须实现Serializable或者Externalizable,否则会抛出NotSerializableException异常

  9. 对象的序列化:

    1. 凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:
      1. private static final long serialVersionUID;
      2. serialVersionUID用来表明类的不同版本间的兼容性。即其目的是以序列化对象进行版本控制,有关各版本反序列化时是否兼容
      3. 如果没有显示定义这个静态变量,它的值是Java运行时环境根据类的内部细节自动生成的,若类的实例化变量做了修改,serialVersionUID可能发生变化,导致已经序列化的对象无法反序列化,因此需要用户显示定义声明
    2. Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行序列化,否则就会出现序列化版本不一致的异常:InvaildCastException
    3. 除了当前类需要实现Serializable接口外,还必须保证颞部所有的属性也必须是可序列化的,基本数据类型默认可序列化,自定义类需要用户实现Serializable接口和提供serialVersionUID,自定义类内部还有自定类,也需要进行相同的操作
  10. ObjectInputOutputStreamTest

    import org.junit.Test;
    
    import java.io.*;
    
    /**
     * @Author: xuehai.XUE
     * @MailBox: xuehai.xue@qq.com
     * @Date: 2021/3/27 14:56
     * @Description:
     */
    public class ObjectInputOutputStreamTest {
    
        @Test
        /** 序列化过程:将内存中的Java对象保存到磁盘中或通过网络传输出去
         *  使用ObjectOutputStream
         */
        public void testObjectOutputStream(){
            ObjectOutputStream oos = null;
            try {
                //1. 创建ObjectOutputStream的实例化对象
                oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
                //2. 向oos对象中写入一个字符串对象
                oos.writeObject(new String("buttercup"));
                //刷新操作
                oos.flush();
    
                //向oos对象中写入一个Person对象
                oos.writeObject(new Person("Biggy", 22));
                oos.flush();
    
                //向oos对象中写入一个带Account的对象
                oos.writeObject(new Person("biggy", 22, 1001, new Account(12145.0)));
                oos.flush();
    
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(oos != null){
                    try {
                        oos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
    
        @Test
        /** 反序列化过程:将磁盘中或网络中下载的对象还原为内存中的一个Java对象
         *  使用ObjectInputStream实现
         */
        public void testObjectInputStream(){
            ObjectInputStream ois = null;
            try {
                ois = new ObjectInputStream(new FileInputStream("object.dat"));
    
                Object obj = ois.readObject();
                String str = (String)obj;
                System.out.println(str);
    
                Person p = (Person)ois.readObject();
                System.out.println(p);
    
                Person p1 = (Person)ois.readObject();
                System.out.println(p1);
    
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } finally {
                if(ois != null){
                    try {
                        ois.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    Person.java& Account.java

    import java.io.Serializable;
    
    /**
     * @Author: xuehai.XUE
     * @MailBox: xuehai.xue@qq.com
     * @Date: 2021/3/27 15:05
     * @Description:
     */
    public class Person implements Serializable {
    
        public static final long serialVersonUID = 4859126156521L;
    
        private String name;
        private int age;
        private int id;
        private Account acct;
    
    
        public Person() {
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public Person(String name, int age, int id, Account acct) {
            this.name = name;
            this.age = age;
            this.id = id;
            this.acct = acct;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public Account getAcct() {
            return acct;
        }
    
        public void setAcct(Account acct) {
            this.acct = acct;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", id=" + id +
                    ", acct=" + acct +
                    '}';
        }
    }
    class Account implements Serializable{
        private static final long serialVersionUID = 45649815L;
    
        private double balance;
    
        public Account() {
        }
    
        public Account(double balance) {
            this.balance = balance;
        }
    
        public double getBalance() {
            return balance;
        }
    
        public void setBalance(double balance) {
            this.balance = balance;
        }
    
        @Override
        public String toString() {
            return "Account{" +
                    "balance=" + balance +
                    '}';
        }
    }
    
2.随机存取文件流(RandomAccessFile)
  1. RandomAccessFile声明在java.io包下,但直接继承于java.lang.Object类。并且它实现了DataInput、DataOutput这两个接口,意味着这个类既可以写也可以读,既可以作为输入流、也可以是输出流

  2. RandomAccessFile类支持“随机访问”的方式,程序可以直接跳到文件的任意地方进行读、写文件

    1. 支持只访问文件的部分内容
    2. 可以向已存在的文件后追加内容
  3. RandomAccessFile对象包含一个记录指针,用以标识当前读写处的位置;RandomAccessFile类的对象可以自由移动记录指针

    1. long getFilePointer():获取文件记录指针的当前位置
    2. void seek(long pos):将文件记录指针定位到pos位置
  4. RandomAccessFile的构造器:

    1. public RandomAccessFile(File file, String mode)
    2. public RandomAccessFile(String name, String mode)
    3. 创建RandomAccessFile类的实例需要指定一个mode参数,该参数指定RandomAccessFile的访问模式
      1. r:以只读的方式打开
      2. rw:打开以便读取和写入
      3. rwd:打开以便读取和写入,同步文件内容的更新
      4. rws:打开以便读取和写入,同步文件和元数据的更新
      5. 每次write数据时,”rw“模式不会立即写到硬盘中;而”rwd“模式下,数据会被立刻写入硬盘。如果写数据的过程中发生异常,”rwd“模式中已被write的数据被保存到硬盘,而”rw“模式下数据则全部丢失
    4. 如果模式为只读”r“。则不会创建文件,而是会读取一个已经存在的文件,如果读取的文件不存在则会出现异常。如果模式为”rw“读写模式,若文件不存在,则会去创建文件,反之,存在则不会创建。
    5. 对于已经存在的文件,将数据写出文件的过程中,会对原有文件的数据从头进行覆盖
  5. RandomAccessFile读写测试

    import org.junit.Test;
    
    import java.io.IOException;
    import java.io.RandomAccessFile;
    
    /**
     * @Author: xuehai.XUE
     * @MailBox: xuehai.xue@qq.com
     * @Date: 2021/3/27 15:57
     * @Description:
     */
    public class RandomAccessFileTest {
    
        @Test
        public void test1(){
            RandomAccessFile raf1 = null;
            RandomAccessFile raf2 = null;
            try {
                //1. 创建随机存取文件流的对象,并指定实例化对象的读取模式
                raf1 = new RandomAccessFile("UnlimitedProgress.jpg", "r");
                raf2 = new RandomAccessFile("UnlimitedProgress.jpg", "rw");
    
                //2. 读写操作
                byte[] buffer = new byte[1024];
                int len;
                while ((len = raf1.read(buffer)) != -1){
                    raf2.write(buffer,0,len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //3. 关闭流资源
                if(raf2 != null){
                    try {
                        raf2.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }if(raf1 != null){
                    try {
                        raf1.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
  6. RandomAccessFile对已有文件覆盖测试,以及使用RandomAccessFile实现”插入“效果

    import org.junit.Test;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    
    /**
     * @Author: xuehai.XUE
     * @MailBox: xuehai.xue@qq.com
     * @Date: 2021/3/27 15:57
     * @Description:
     */
    public class RandomAccessFileTest {
        
        @Test
        public void test2(){
            RandomAccessFile raf1 = null;
            try {
                raf1 = new RandomAccessFile("hello.txt", "rw");
                //先提供一个hello.txt文件内容为“abcdefghijklmnopq”
                raf1.write("xyz".getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(raf1 != null){
                    try {
                        raf1.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        @Test
        /** 从指定位置开始覆盖文件内容 */
        public void test3(){
            RandomAccessFile raf1 = null;
            try {
                raf1 = new RandomAccessFile("hello.txt", "rw");
                //先提供一个hello.txt文件内容为“abcdefghijklmnopq”
                //将指针调到角标为三的位置,从第四个字母开始覆盖
                raf1.seek(3);
                raf1.write("xyz".getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(raf1 != null){
                    try {
                        raf1.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        @Test
        /** 使用RandomAccessFile实现数据的插入效果 */
        public void test4(){
            RandomAccessFile raf1 = null;
            try {
                raf1 = new RandomAccessFile("hello1.txt","rw");
    
                raf1.seek(3);
    
                //保存指针3后面的数据到StringBuilder sb中
                StringBuilder sb = new StringBuilder((int) new File("hello1.txt").length());
    
                byte[] buffer = new byte[20];
                int len;
                while ((len = raf1.read(buffer)) != -1){
                    sb.append(new String(buffer,0,len));
                }
    
                //调回指针,写入xyz
                raf1.seek(3);
                raf1.write("xyz".getBytes());
    
                //将StringBuilder中的数据写入到文件中
                raf1.write(sb.toString().getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //关闭流资源
                if(raf1 != null){
                    try {
                        raf1.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
3.NIO.2中Path、Paths、Files类的使用
  1. JavaNIO(New IO, Non-Blocking IO)是从Java1.4版本开始引入的一套新的IO API,可以替代Java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的操作、基于通道的操作;而IO是面向流的操作。NIO将以更加高效的方式进行文件的读写操作

  2. JavaAPI中提供了两套NIO,一套是针对标准的输入输出NIO,另一套就是网络编程NIO

  3. java.nio.channels.Channel下有以下常用子类:

    1. FileChannel:处理本地文件
    2. SocketChannel:TCP网络编程客户端的Channel
    3. ServerSoctketChannel:TCP网络编程的服务器端的Channel
    4. DatagramChannel:UDP网络编程中发送端和接收端的Channel
  4. NIO.2:随着JDK1.7的发布,Java对NIO进行了扩展,增强了对文件处理和文件系统特性的支持,以至于之为NIO.2

  5. Path、Paths、Files核心API:

    1. 早期Java只提供了一个File类来访问文件系统,但File类的功能比较有限,所提供的方法性能也不高,而且,大多数方法在出错时只返回事变,并不会提供异常信息

    2. NIO.2为了弥补这种不足,引入了Path接口,代表一个与平台无关的路径,描述了目录结构中文件的位置。Path可以看成时File类的升级版本,实际引用的资源也可以不存在

    3. JDK1.7以前:

      1. import java.io.File;

        File file = new File(“index.html”);

    4. JDK1.7以后:

      1. import.java.nio.fiie.Path;

        import.java.nio.file.Paths;

        Path path = Paths.get(“index.html”);

    5. NIO.2在java.nio.file包下还提供了Files、Paths工具类,Files包含了大量静态的工具方法来操作文件;Paths则包含了两个返回Path的静态工厂方法。

    6. Paths类提供的静态get()方法用来获取Path对象:

      1. static Path get(String first, String … more):用于将多个字符串串联成路径
      2. static Path get(URI uri):返回指定uri对应的Path路径
    7. Path常用方法:

      1. String toString():返回调用Path对象的字符串表示形式
      2. boolean startsWith(String path):判断是否以path路径开始
      3. boolean endsWith(String path):判断是否以path路径结束
      4. boolean isAbsolute():判断是否是绝对路径
      5. Path getParent():返回Path对象包含整个路径,不包含Path对象指定的文件路径
      6. Path getRoot():返回调用Path对象的根路径
      7. Path getFileName():返回与调用Path对象关联的文件名
      8. int getNameCount():返回Path根目录后面元素的数量
      9. Path getName(int idx):返回指定索引位置idx的路径名称
      10. Path toAbsolutePath():作为绝对路径返回调用Path对象
      11. Path resolve(Path p):合并两个路径,返回和病后的路径对应的Path对象
      12. File toFile():将Path转化为File类的对象
    8. Files类常用的方法:

      1. Path copy(Path src, Path dest, CopyOption … how):文件的复制
      2. Path createDirectory(Path path, FileAttribute<?> … attr):创建一个目录
      3. Path createFile(Path path, FileAttribute<?> … arr):创建一个文件
      4. void delete(Path path):删除一个文件/目录,如果不存在执行报错
      5. void move(Path src, Path dest, CopyOption … how):将src移动到dest位置
      6. long size(Path path):返回path指定文件的大小
    9. File类常用方法:用于判断

      1. boolean exists(Path path, LinkOption … opts):判断文件是否存在
      2. boolean isDriectory(Path path, LinkOption … opts):判断是否是目录
      3. boolean isRegularFile(Path path, LinkOption … opts):判断是否是文件
      4. boolean isHidden(Path path):判断是否是隐藏文件
      5. boolean isReadable(Path path):判断文件是否可读
      6. boolean isWritable(Path path):判断文件是否可写
      7. boolean notExists(Path path, LinkOption … opts):判断文件是否不存在
    10. Files常用方法,用于操作内容:

      1. SeekableByteChannel newByteChannel(Path path, LinkOption … opts):获取指定文件的连接,how指定打开方式
      2. DirectoryStream<path> newDirectoryStream(Path path):打开path指定的目录
      3. InputStream newInputStream(Path path, LinkOption … opts):获取InputStream的对象
      4. OutputStream newOutputStream(Path path, LinkOption … opts):获取OutputStream的对象

image-20210303180846928

STAY ANGER!!!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值