Java的IO流

IO流是什么?

IO可以实处理设备之间的数据传输(比如网络传输、读写文件等)

IO流的分类:

按照数据单位不同可以分为:及字节流和字符流。

         字节流: 一般是非文本的数据,比如时字符流、字节流

         字符流: 一般是用于文本文件。

按照数据的不同可以分为:输入流,和输出流。

         输入流:是从磁盘读取到程序中

         输出流:是从程序读取到磁盘

按照角色不同可以分为:节点流、处理流。

         节点流: 直接作用在文件上的流。

         处理流:作用在节点流上面的流,可以加快节点流的传输速度,或者是其他的功能。

IO流所有的类都是由四个基本的基类来实现的:

抽象基类输入流输出流
字节流InputStreamOutputStream
字符流ReaderWriter

File类的使用:

File类的一个对象就代表一个文件或者是一个文件目录。File类的功能涉及到文件目录的创建、删除、重命名、修改时间等操作但是并不涉及文件的读写操作,如果想要进行读写操作就要涉及流了。File对象会作为参数传输到流的构造器中指明读写的对象。

字符输入流:FileReader

实例:

  @Test
    public void  iotest()  {
        FileReader fileReader = null;
        try {
            File file = new File("hello.txt");

            fileReader = new FileReader(file);

            int read = fileReader.read();  //和之前介绍的迭代器的指针相似

            while (read!=-1){
                System.out.println((char) read);
                read=fileReader.read();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileReader!=null) {
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

        需要注意的是: 虽然Java中有自己的垃圾回收机制但是对与超出程序之内之间的链接并不会进行垃圾回收,所以需要我们需要手动关闭IO流。在异常处理机制 中的try-catch-finally结构中finally中的内容一定会执行,我们可以将关闭流的操作放在finally中,随之又产生另一个问题,IO流不一定会创建成功,如果创建不成功的话在finally中执行关闭流的操作就会产生空指针异常,所以在执行关闭流操作之前进行判断是不是是不是流创建成功。

字符输出流:FileWriter

 @Test
    public void  sjdk()  {
        FileWriter fileWriter = null;
        try {
            File file = new File("hello.txt");
    
            fileWriter = new FileWriter(file,true);//参数一是需要操作的文件,参数二是选择是否覆盖原有文件
    
            fileWriter.write("高小军");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

        if (fileWriter!=null) {

            try {
                fileWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

需要注意的是FileWriter(参数一,参数二);: 其中参数一是需要操作的文件,参数二选择是否覆盖原有的内容(True 表示不进行覆盖,false表示进行覆盖)

字节输入流:FileInputStream  : 和字符输入流相似

字节输出流:FileOutputStream:和字符输出流相似

缓冲流:

缓冲流是处理流的一种,缓冲流可以提高文件的读写效率。

实例:(已复制照片为例)

  @Test
    public   void  sjdk1()  {
        BufferedInputStream bufferedInputStream = null;
        BufferedOutputStream bufferedOutputStream = null;
        try {
            FileInputStream fileInputStream = new FileInputStream("李芳.jpg");
            FileOutputStream fileOutputStream = new FileOutputStream("李芳1.jpg");

            bufferedInputStream = new BufferedInputStream(fileInputStream);
            bufferedOutputStream = new BufferedOutputStream(fileOutputStream);

            int read = bufferedInputStream.read();
            while(read!=-1){
                bufferedOutputStream.write(read);
                read = bufferedInputStream.read();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bufferedInputStream!=null){
                try {
                    bufferedInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bufferedOutputStream!=null){
                try {
                    bufferedOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

需要注意的是:对于FileInputStream(),FileOutputStream()中的参数要传入对应的节点流对象。

再关闭流的时候,只需要关闭处理流,就会自动的关闭对应的节点流。

转换流:

转换流也是处理流中的一种,提供了字符流和字节流之间的相互转换。InputStreamReader可以将输入流的字节流转换成字符流,OutputStreamWriter  可以将输出流的 字符流转换成字节流。也就是解码和编码的过程,解码就是,字节、字节数组----->字符、字符串(也就是从看不懂到能看懂),编码就是解码的反过程。

示例:以复制文件为例

@Test
    public void  k() {
        InputStreamReader inputStreamReader = null;
        OutputStreamWriter outputStreamWriter = null;
        try {
            FileInputStream fileInputStream = new FileInputStream("hello.txt");
            FileOutputStream fileOutputStream = new FileOutputStream("hello2.txt");
            inputStreamReader = new InputStreamReader(fileInputStream);//输入转换流
            outputStreamWriter = new OutputStreamWriter(fileOutputStream);//输出转换流
            char[] chars = new char[10];
            int read = inputStreamReader.read(chars);//是将准换流读取的数据先存储在数组中
            while(read!=-1){
                outputStreamWriter.write(chars,0,read);//存入数组【0,read】段的数据
                read=inputStreamReader.read(chars);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
             if (inputStreamReader!=null){
                 try {
                     inputStreamReader.close();
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
             }
            if (outputStreamWriter!=null){
                try {
                    outputStreamWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

注意outputStreamWriter.write(chars,0,read);

方法中的参数:第一个参数是要输出的数组,参数二和参数三组合起来形成数组的下标范围,在这个范围中的数据进行输出。

目的:在完全读取文件内容的时候,最后一次读取的内容长度可能并不是数组的长度,所以就要进行限制数组的下标,如果不进行限制的话   在最后一次进行从数组中读取数据时,会把上一次填充数组的数据读取出来。

 对象流 :

用于存储和读取基本数据类型的的数据或者是对象的处理流,主要的目的是把对象写入到数据源中,也能把数据源还原出来。

对象流的两大核心:

序列化:是输出流 将内存中的对象写到硬盘 ObjectOutputSteam

反序列化:是输入流将硬盘的对象还原到内存  ObjectInputStream

对象序列化原理:

    允许把内存中的Java对象转换成与平台无关的二进制流,从而允许二进制流持久的保存在磁盘上或者是通过网络传输到另一个网络接节点,当其他程序获取到了这种二进制流,可以恢复到Java对象。

自定义序列化类

public  class Person  implements Serializable{
     public    static final long serialVersionUID = 4454545454554545L;  //序列化版本标识符的静态变量
     private   Account  account;
     private  String name;
     private  Integer  age;

     public String getName() {
         return name;
     }

     public void setName(String name) {
         this.name = name;
     }

     public Integer getAge() {
         return age;
     }

     public void setAge(Integer age) {
         this.age = age;
     }


     public Person(String name, Integer age) {
         this.name = name;
         this.age = age;
     }

     @Override
     public String toString() {
         return "Person{" +
                 "name='" + name + '\'' +
                 ", age=" + age +
                 '}';
     }
 }
 class      Account{
       public    static  final  long serialVersionUID = 4454545454554545L;}

自定义序列化类需要注意的点:

    这个类对象如果想要被序列化:

  • 要实现Serializable接口、
  • 添加序列化标识符、
  • 如果属性的类型是自定义类那么这个类也需要支持序列化,基本数据类型已经实现了序列化。
  •       ObjectOutputSteam  和ObjectInputStream不能序列化static 和tranaient  修饰的成员变量

序列化和反序列化的过程:

  //序列化过程
    @Test
    public  void sjd()  {
        ObjectOutputStream objectOutputStream = null;
        try {
            FileOutputStream fileOutputStream = new FileOutputStream("Object.dat");
            objectOutputStream = new ObjectOutputStream(fileOutputStream);
            Person  sb = new Person("高战军", 99);
            objectOutputStream.writeObject(sb);
            objectOutputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {if (objectOutputStream!=null){

            try {
                objectOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        }
    }
    //反序列化过程
    @Test
    public   void  sss()  {

        ObjectInputStream objectInputStream = null;
        try {
            FileInputStream fileInputStream = new FileInputStream("Object.dat");
            objectInputStream = new ObjectInputStream(fileInputStream);
            Object object = objectInputStream.readObject();
            Person person  =   (Person) object;
            System.out.println(person);
            Object object2 = objectInputStream.readObject();
            String   string2 = (String)object2;
            System.out.println(string2);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (objectInputStream!=null){
                try {
                    objectInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

需要注意的是序列化的时候默认添加到原有文件的后面,不会覆盖原有的文件内容。

反序列化的过程中  需要注意怎样获取数据

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值