Java知识点_IO操作那些事

前言:

在刚接触Java的时候对于IO的相关知识点整体掌握的还是比较牢靠的,在从事android相关的工作开发后,对于java IO的相关知识逐渐的模糊起来。其一应该是android中直接使用IO相关的功能比较少,大多数都是封装好的第三方类库。其二即使使用到了IO操作封装成为一个工具类之后,后期回头看的次数相对较少。总之对于Java IO 的相关知识使用的少,缺少总结。
为此这篇文章主要介绍IO类之间的关系,针对在android开发中常用到的IO 操作类给出实例代码参考。

"输入"和"输出"在刚接触java IO的时候这两个概念给我带来了一丝的疑惑。输入的对象是谁?又输出到哪里?

输入流可以理解为向内存[程序内存]输入输出流可以理解为从内存[程序内存]输出

Java的IO包主要关注的是从原始数据源的读取以及输出原始数据到目标媒介。
一个程序需要InputStream或者Reader从数据源读取数据,需要OutputStream或者Writer将数据写入到目标媒介中
在这里插入图片描述
能够理解 IO 输入和输出 概念,对java IO的学习有重要的帮助。

IO类概述表

Java的IO包主要关注的是从原始数据源的读取以及输出原始数据到目标媒介。
一个程序需要InputStream或者Reader从数据源读取数据,需要OutputStream或者Writer将数据写入到目标媒介中:

在这里插入图片描述
根据类的关系又可以划分:

在这里插入图片描述

  • OutputStream、InputStream是操作字节流的抽象类无法直接使用。需要根据操作对象选择合适的子类操作。
  • FileOutputStream、FileInputStream对 文件操作
  • ObjectInputStream 和ObjectOutputStream 对 java对象操作
  • DataInputStream 和DataOutputStream 对 java基本类型和字符串操作
  • BufferedInputStream和BufferedOutputStream 组合流:将流整合起来以便实现更高级的输入和输出操作。比如,一次读取一个字节是很慢的,所以可以从磁盘中一次读取一大块数据,然后从读到的数据块中获取字节。为了实现缓冲,可以把InputStream包装到BufferedInputStream中。代码示例:
InputStream input = new BufferedInputStream(new FileInputStream("c:\\data\\input-file.txt"));
  • Reader、Writer是操作字符的抽象类无法直接使用。需要根据操作对象选择合适的子类操作。
  • InputStreamReader、OutputStreamWriter 这两个类把字节流转换成字符流,中间做了数据的转换,类似适配器模式的思想。
  • InputStream的read()方法返回一个字节,意味着这个返回值的范围在0到255之间(当达到流末尾时,返回-1),
  • Reader的read()方法返回一个字符,意味着这个返回值的范围在0到65535之间(当达到流末尾时,同样返回-1)。
字节流常用类:
一、FileInputStream和FileOutputStream

读取文件内容和写入文件内容

    /**
     * 测试 输入流和输出流
     * 目标:读取 atext.txt 中的内容   写到 btext.txt中
     * 读取 apic.jpeg 中的内容   写到 bpic.jpeg中
     */
    private static void testInputAndOutputStream1() {
        InputStream is = null;
        OutputStream os = null;
        // 操作文件
//        File inFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/atext.txt");
//        File outFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/btext.txt");

        // 操作图片 apic.jpeg
        File inFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/apic.jpeg");
        File outFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/bpic.jpeg");
        if (outFile.exists()) {
            outFile.delete();
            Utils.printLog("testInputAndOutputStream ", "outFile 已存在 删除!");
        }

        try {
            is = new FileInputStream(inFile);
            os = new FileOutputStream(outFile);// 如果文件不存在 会自动创建

            int temp = is.read();
            while (temp != -1) {
                os.write(temp);
                temp = is.read();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        	// 关流 模板代码 后续样例省略
            try {
                if (is != null) {
                    is.close();
                }
                if (os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

int read() :每次只读一个字节,如果文件特别大,这样操作会有效率问题
int read(byte b[]) :一次性读取一个字节数组的方式,比一次性读取一个字节的方式快的多,所以,尽可能使用这两个方法代替read()方法。

    /**
     * 测试 输入流和输出流
     * 目标:  is.read() 每次只读一个字节,如果文件特别大,这样操作会有效率问题
     * Java I/O默认是不缓冲流的,所谓“缓冲”就是先把从流中得到的一块字节序列暂存在一个被称为buffer的内部字节数组里,
     * 然后你可以一下子取到这一整块的字节数据,没有缓冲的流只能一个字节一个字节读,效率孰高孰低一目了然。
     *
     * 有两个特殊的输入流实现了缓冲功能,一个是我们常用的BufferedInputStream
     */
    private static void testInputAndOutputStream2() {
        InputStream is = null;
        OutputStream os = null;
        byte[] bufferRead = new byte[512];
        int numberRead = 0; // numberRead的目的在于防止最后一次读取的字节小于buffer长度,
        // 操作文件

        File inFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/atext.txt");
        File outFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/btext.txt");

        // 操作图片 apic.jpeg
//        File inFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/apic.jpeg");
//        File outFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/bpic.jpeg");

        if (outFile.exists()) {
            outFile.delete();
            Utils.printLog("testInputAndOutputStream ", "outFile 已存在 删除!");
        }
        try {
            is = new FileInputStream(inFile);
            os = new FileOutputStream(outFile);

            while ((numberRead = is.read(bufferRead)) != -1) {
                os.write(bufferRead, 0, numberRead);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关流
        }
    }

有两个特殊的输入流实现了缓冲功能,一个是我们常用的BufferedInputStream、BufferedOutputStream

二、BufferedInputStream和BufferedOutputStream

BufferedInputStream BufferedInputStream能为输入流提供缓冲区,能提高很多IO的速度。你可以一次读取一大块的数据,而不需要每次从网络或者磁盘中一次读取一个字节。特别是在访问大量磁盘数据时,缓冲通常会让IO快上许多。 为了给你的输入流加上缓冲,你需要把输入流包装到BufferedInputStream中,代码如下:

InputStream input = new BufferedInputStream(new FileInputStream("c:\\data\\input-file.txt"));

你可以给BufferedInputStream的构造函数传递一个值,设置内部使用的缓冲区设置大小(译者注:默认缓冲区大小8 * 1024B),就像这样:

InputStream input = new BufferedInputStream(new FileInputStream("c:\\data\\input-file.txt"), 8 * 1024);
    /**
     * 测试 输入流和输出流
     * 目标:  is.read() 每次只读一个字节,如果文件特别大,这样操作会有效率问题
     *       使用 BufferedInputStream
     *
     * 有两个特殊的输入流实现了缓冲功能,一个是我们常用的BufferedInputStream
     */
    private static void testInputAndOutputStream3() {
        InputStream is = null;
        OutputStream os = null;
        byte[] bufferRead = new byte[512];
        int numberRead = 0; // numberRead的目的在于防止最后一次读取的字节小于buffer长度,
        // 操作文件

        File inFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/atext.txt");
        File outFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/btext.txt");

        // 操作图片 apic.jpeg
//        File inFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/apic.jpeg");
//        File outFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/bpic.jpeg");

        if (outFile.exists()) {
            outFile.delete();
            Utils.printLog("testInputAndOutputStream ", "outFile 已存在 删除!");
        }

        try {
            is = new BufferedInputStream(new FileInputStream(inFile));
            os = new BufferedOutputStream(new FileOutputStream(outFile));

            while ((numberRead = is.read(bufferRead)) != -1) {
                os.write(bufferRead, 0, numberRead);
                os.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关流
        }
    }
三、DataInputStream 和DataOutputStream
   /**
     * 写入基本变量和字符串至文件
     * 从文件中读取基本变量和字符串 
     */
    private static void testDataOutputStream() {
        File file = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/datatext.txt");

        DataOutputStream dos = null;
        DataInputStream dis = null;
        if (file.exists()) {
            file.delete();
        }

        try {
            dos = new DataOutputStream(new FileOutputStream(file));
            dis = new DataInputStream(new FileInputStream(file));

            dos.writeUTF("小米");
            dos.writeInt(10);
            dos.writeDouble(1.10);

            // 有用吗???
            dos.flush();
            
            // 注意:写入数据和读取数据 顺序保持一致
            // 否则:java.io.EOFException 错误
            String name = dis.readUTF();
            int age = dis.readInt();
            double color = dis.readDouble();
            Utils.printLog("", "name:" + name + " age:" + age + " color:" + color);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关流
        }
    }
四、ObjectInputStream 和ObjectOutputStream

如果你希望类能够序列化和反序列化,必须实现Serializable接口,就像所展示的ObjectInputStream和ObjectOutputStream例子一样。
ObjectInputStream能够让你从输入流中读取Java对象,而不需要每次读取一个字节。你可以把InputStream包装到ObjectInputStream中,然后就可以从中读取对象了。代码如下:

   /**
     * 将对象写入 文件
     * 从文件中读取 对象
     */
    private static void testObjectStream() {
        File inFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/aotext.txt");
        File outFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/botext.txt");
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        if (inFile.exists()) {
            inFile.delete();
        }
        try {
            // 写入
            oos = new ObjectOutputStream(new FileOutputStream(outFile));
            oos.writeObject(new Dog("aa", "10", "red"));
            oos.writeObject(new Dog("bb", "11", "green"));
            oos.writeObject(new Dog("cc", "12", "red"));
            oos.writeObject(new Dog("dd", "13", "yellow"));
            //插入null是用来判断是否读取到结尾
            //写入结束标志方便读取(非常重要,如果不写入,在读取的时候无法定位读取结束);
            //读取的时候就会报  java.io.EOFException  异常
            oos.writeObject(null);


            // 读取
            ois = new ObjectInputStream(new FileInputStream(outFile));
            Object obj = null;
            while ((obj = ois.readObject()) != null) {
                Dog dog = (Dog) obj;

                Utils.printLog("testObjectStream", dog.toString());
            }

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            // // 关流
        }

    }

写入数组、读取数组

 private static void testObjectArrStream() {
        File inFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/aotext.txt");
        File outFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/botext.txt");
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        if (inFile.exists()) {
            inFile.delete();
        }
        try {
            // 写入 数组
            Dog[] dogArr = new Dog[10];
            for (int i = 0; i < dogArr.length; i++) {
                Dog dog = new Dog("aa"+i, "" + (10 + i), "red");
                dogArr[i]=dog;
            }
            oos = new ObjectOutputStream(new FileOutputStream(outFile));

            oos.writeObject(dogArr);

            // 读取 数组
            ois = new ObjectInputStream(new FileInputStream(outFile));
            Dog[] dogs = (Dog[]) ois.readObject();

            for (Dog dog : dogs) {
                Utils.printLog("testObjectStream", dog.toString());
            }

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
           // 关流
        }

    }
public class Dog implements Serializable {

    private String name;

    private String age;

    private String color;

    public Dog(String name, String age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    public String getName() {
        return name;
    }

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

    public String getAge() {
        return age;
    }

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

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                ", color='" + color + '\'' +
                '}';
    }
}
字符流常用类
一、BufferedRead 和 BufferedWriter

整合Reader和Writer 和字节流一样,Reader和Writer可以相互结合实现更多更有趣的IO,工作原理和把Reader与InputStream或者Writer与OutputStream相结合类似。举个栗子,可以通过将Reader包装到BufferedReader、Writer包装到BufferedWriter中实现缓冲。以下是例子:

Reader reader = new BufferedReader(new FileReader(...));
Writer writer = new BufferedWriter(new FileWriter(...));
  /**
     * 使用 inputStreamReader 和 outputStreamWriter
     */
    private static void testReadAndWriter1() {
        Reader reader = null;
        Writer writer = null;


        File readFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/reader.txt");
        File writerFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/writer.txt");


        try {
            reader = new InputStreamReader(new FileInputStream(readFile));
            writer = new OutputStreamWriter(new FileOutputStream(writerFile));
            char[] chars = new char[512];
            int line = 0;
            while ((line = reader.read(chars)) != -1) {
                writer.write(chars, 0, line);
                writer.flush();
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关流
        }

    }
二、InputStreamReader和OutputStreamWriter

整合Reader与InputStream 一个Reader可以和一个InputStream相结合。如果你有一个InputStream输入流,并且想从其中读取字符,可以把这个InputStream包装到InputStreamReader中。把InputStream传递到InputStreamReader的构造函数中:

Reader reader = new InputStreamReader(inputStream);
  /**
     * 使用 bufferedRead
     */
    private static void testReadAndWriter2() {
        Reader reader = null;
        Writer writer = null;


        File readFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/reader.txt");
        File writerFile = new File("/Users/fumm/work/my_project/my_lib/CustomView/java_lib/src/main/res/writer.txt");
        if (writerFile.exists()) {
            writerFile.delete();
        }

        try {
//            reader = new InputStreamReader(new FileInputStream(readFile));
//            writer = new OutputStreamWriter(new FileOutputStream(writerFile));
            reader = new BufferedReader(new FileReader(readFile));
            writer = new BufferedWriter(new FileWriter(writerFile));


            char[] chars = new char[512];
            int line = 0;
            while ((line = reader.read(chars)) != -1) {
                writer.write(chars, 0, line);
                writer.flush();
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关流
        }
    }
总结:

本文主要梳理Java IO类之间的操作和转换。并通过实例代码加深对IO的理解。对android开发中常见的IO 操作类进行实践。内容比较基础大致对Java IO 知识做了基础的回顾。

参考:
Java IO教程
Java IO最详解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值