IO流

1 file类使用

点击进入

2 IO流概述

2.1 流的三种分类

  • 流向 : 输入流和输出流
  • 数据单位 : 字节流和字符流
  • 流的角色 : 节点流和处理流

2.2 四个IO流中的抽象基类

  • OutputStream 字节输出流
  • Inputstream 字节输入流
  • Reader 字符输入流
  • Writer 字符输出流

3 文件流(节点流)

3.1 FileOutputStream

字节流操作不会用到缓存区,不需要刷新缓存,fileOutputStream.flush();但字节流操作时用到缓存(内存),一般会调用close()方法关闭时刷新缓存。

面试题:close()和flush()的区别?

A:close()关闭流对象,但是先刷新一次缓冲区,关闭之后,流对象不可以继续再使用了。
B:flush()仅仅是刷新缓冲区(一般写字符时要用,因为字符是先进入的缓冲区),流对象还可以继续使用

构造方法

  • public FileOutputStream(File file) throws FileNotFoundException{}
    若使用第一个默认以后写都是把之前的清空再写

  • public FileOutputStream(File file,boolean append) throws FileNotFoundException{}
    第二个参数为true,则字节将写入文件的末尾而不是开头。

public static void main(String[] args) {
        FileOutputStream fileOutputStream = null;

        try {
            fileOutputStream = new FileOutputStream("F:\\a.txt");
            String value = "你好世界";
            byte[] bytes = value.getBytes();
            fileOutputStream.write(bytes);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            if(fileOutputStream != null){
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

    }

3.2 FileInputStream

public static void main(String[] args) {

        InputStream f = null;
        int len = 0;   //记录读取到的字节
        try {
            f = new FileInputStream("F:\\a.txt");
             //int read​(byte[] b):一次读取一个字节数组,输入流会把读取到的内容放入到这个字节数组中,并返回读取到的个数, 如果读取结束返回-1.
            while((len = f.read()) != -1){    //从文件中读取一个字节数的数据。并返回读取到的这个字节。 如果读取结束,返回的是-1.

                System.out.println((char) len);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(f != null){
                    f.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

3.3 FileReader

 public static void main(String[] args) {
        Reader reader = null;
        try {
            reader = new FileReader("F:\\a.txt");
            char[] str = new char[55];

            int len = 0;
            while((len = reader.read(str)) != -1){

                System.out.println(str);
            }


        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            try {
                if(reader != null){
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

3.4 FileWriter

需要注意的是构造方法中的是否追加参数,还有就是writer的write并没有将数据直接写进文件而是保存在缓冲区,flush方法才是将缓冲去的数据写入到文本。

public static void main(String[] args) {
        Writer writer = null;

        try {
            writer = new FileWriter("F:\\a.txt",true);
            writer.append("你好");
            writer.write("你好你好");

        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            if(writer != null){
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }


        }
    }

4 缓冲流

目的:通过使用缓存,加快读取和写入数据的速度。
原因:内部提供了一个缓冲区,默认情况下是8192,即8kb
如果需要大量的读写,使用缓冲流效果更好

4.1 BufferedOutputStream

4.2 BufferedInputStream

4.3 BufferedWriter

4.4 BufferedReader

操作和3中类似

4.4 案例:实现图片复制

 public static void main(String[] args) {

        BufferedInputStream bufferedInputStream = null;
        BufferedOutputStream bufferedOutputStream = null;

        try {
            bufferedInputStream = new BufferedInputStream(new FileInputStream("F:\\01.jpg"));

            bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("F:\\02.jpg"));

            byte[] bytes = new byte[1024];
            int len = 0;
            while((len = bufferedInputStream.read(bytes)) != -1){
                bufferedOutputStream.write(bytes,0,len);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } 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();
                }
            }
        }
    }

4 转换流

转化流属于字符流

4.1 OutputStreamWriter

OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的字符编码表,将要写入流中的字符编码成字节。它的作用的就是,将字符串按照指定的编码表转成字节,在使用字节流将这些字节写出去

 public static void main(String[] args) {

        FileOutputStream fileOutputStream = null;
        OutputStreamWriter outputStreamWriter = null;

        try {
            fileOutputStream = new FileOutputStream("F:\\a.txt");

            outputStreamWriter = new OutputStreamWriter(fileOutputStream,"utf-8");
            outputStreamWriter.write("你好");

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {


            if(outputStreamWriter != null){
                try {
                    outputStreamWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(fileOutputStream != null){
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

4.2 InputStreamReader

InputStreamReader 是字节流通向字符流的桥梁:它使用指定的字符编码表读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。

public static void main(String[] args) {
        FileInputStream fileInputStream = null;

        //将字节转换为字符
        InputStreamReader inputStreamReader = null;

        try {
            fileInputStream = new FileInputStream("F:\\a.txt");
            inputStreamReader = new InputStreamReader(fileInputStream,"utf-8");

            char[] buf = new char[20];
            int len = 0;
            while((len = inputStreamReader.read(buf)) != -1){
                String str = new String(buf,0,len);
                System.out.println(str);

            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }

5 对象流

有的时候,我们可能需要将内存中的对象持久化到硬盘上,或者将硬盘中的对象信息读到内存中,这个时候我们需要使用对象输入输出流。

  • 序列化: 是对象转换成一个字节序列的过程,是一个写操作
  • 反序列化: 一个字节序列转换成对象的过程 ,是一个读操作
  • 当使用对象流写入或者读取对象的时候,必须保证该对象是序列化的

5.1 ObjectOutputStream(OutputStream out)

 public static void main(String[] args) {

        //序列化:将内存中的java对象读取到硬盘中或通过网络传输出去,使用ObjectOutputStream实现
        ObjectOutputStream objectOutputStream = null;

        try {
            objectOutputStream = new ObjectOutputStream(new FileOutputStream("F:\\object.dat"));
            objectOutputStream.writeObject(new String("我爱it"));
            objectOutputStream.flush();

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(objectOutputStream != null){
                try {
                    objectOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
    

5.2 ObjectInputStream (InputStream in)

public static void main(String[] args) {

        ObjectInputStream objectInputStream = null;

        try {
            objectInputStream = new ObjectInputStream(new FileInputStream("F:\\object.dat"));

            Object o = objectInputStream.readObject();
            String str = (String) o;
            System.out.println(str);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {

            if(objectInputStream != null){
                try {
                    objectInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

5.3 自定义类实现序列化

需要满足的条件

  • 实现Serializable接口
  • 对象所在的类提供常量:序列版本号 public static final Long serializableID = 698515664L; 随便数字多少
  • 要求对象的属性也必须是可序列化的。(基本数据类型本身是可序列化的)
  • static、transient修饰的属性不能被序列化不能被ObjectOutputStream和ObjectIntputStream序列化
public class Person implements Serializable {


    public static final Long serializableID = 698515664L;

    private String name;

    private int age;

    public Person() {
    }

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

    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;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

一般情况下用JSON

6 随机存取文件流

RandomAccessFile

6.1 基础使用

在这里插入图片描述

public static void main(String[] args) {

        //既可以作为输入流又可以作为输出流
        RandomAccessFile randomAccessFile1 = null;
        RandomAccessFile randomAccessFile2 = null;

        try {
            randomAccessFile1 = new RandomAccessFile("F:\\01.jpg","r");
            randomAccessFile2 = new RandomAccessFile("F:\\02.jpg","rw");

            byte[] bytes = new byte[1024];
            int len = 0;
            while((len = randomAccessFile1.read(bytes)) != -1){

                randomAccessFile2.write(bytes,0,len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            if(randomAccessFile1 != null){
                try {
                    randomAccessFile1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(randomAccessFile2 != null){
                try {
                    randomAccessFile2.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


    }

6.2 seek方法

/*
    使用RandomAccessFile实现数据的插入效果
     */
    @Test
    public void test3() throws IOException {

        RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");

        raf1.seek(3);//将指针调到角标为3的位置
        //保存指针3后面的所有数据到StringBuilder中
        StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());
        byte[] buffer = new byte[20];
        int len;
        while((len = raf1.read(buffer)) != -1){
            builder.append(new String(buffer,0,len)) ;
        }
        //调回指针,写入“xyz”
        raf1.seek(3);
        raf1.write("xyz".getBytes());

        //将StringBuilder中的数据写入到文件中
        raf1.write(builder.toString().getBytes());

        raf1.close();

        //思考:将StringBuilder替换为ByteArrayOutputStream
    }

©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页