欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java-输入输出流的简单看法与总结

程序员文章站 2024-03-04 20:39:54
...

Java-输入输出流的简单看法与总结

 为什么Java中关于输入输出流(IO流)的对象为什么这么多,实在难以记忆,这可能是绝大多数人在学习关于Java此内容的问题,下面就来总结一下这个知识点,让这个困难得到解决。

一、理解Java的IO模型和框架

实际上对于Java输入输出流的所有概念在下图中就已经完整地体现了:

Java-输入输出流的简单看法与总结
还有不得不提一下Java的IO框架:
Java-输入输出流的简单看法与总结

弄明白上面两张图,你就可以说已经理解了Java的IO模型。

 首先,需要理解IO流的各个类是用来做什么的。比方说:InputStreamReader 类可以用来做什么,有什么用途?可能这个问题难道你了,因为这个类既包括字节流,也囊括了字符流,到底是哪一个流?

有一个规律:

  1. 末尾的单词决定其是哪一类IO流,所以在此例中,这为字符流;
  2. 开始的单词决定的输入的流类型,或者目的地流类型;
  3. Reader是基于字符的输入操作流,InputStream是基于字节的输入操作流
  4. Writer是基于字符的输出操作流,OutputStream是基于字节的输出操作流
  5. 输出/输出流的分类意味着这个类具有输出/读取的功能方法,而不以为这流本身会主动执行这些方法

 有些既可以是源,也可以是目的地,比如说File,因为我们既可以从文件中读取内容,也可以向文件中写入内容,所以File既可以与InputStream组合,也可以和OutputStream组合;
有些则只能是目的地,或源,比如说InputStream只能和Reader组合,而没有OutputStreamReader的组合。

 综上所述,InputStreamReader类使用来读取字节流数据,得到字符数据来供我对字符流数据进行操作的类,所以这也要求了InputStreamReader类中的大多数方法是基于字符的操作。

注意事项:不要错认为IO流操作过程中只有输出流会对数据进行转换,比如说字节流转为硬盘文件存储起来,输入流同样有转换数据的功能。

除了用于缓冲作用的流,输入流可以一下方式理解:

Java-输入输出流的简单看法与总结
输出流可以这么理解:

Java-输入输出流的简单看法与总结
 对于缓冲IO流的理解:其也是个流对象,不过被称为装饰类流,这主要是通过其对输入/出流对象装饰后,我们不再直接调用输入/出流的读写方法,而是调用它缓冲IO流的读写方法。但是这个理解还是不够到位。所有流对象也是位于内存中的,但是缓冲IO流对象还是一个实管理内存的工具,所以可以凭借此类来和内存直接打交道,优化内存管理,而直接使用输入输出流则没有此功能。

二、活学活用

注意事项:下面的例子没有进行异常处理以及流的关闭操作,实际上不够科学,但是这里不是重点,省略了。

  1. 将一个字符串转为文档储存起来:

面对这样一个例子,我们应当怎么做呢?

我们是否需要一个输出流对象以及一个输出流对象呢?

 其实是不需要的,因为输入流的作用是读取数据至内存(或者特殊的内存块:缓冲IO流),既然String对象以及位于内存中了,不需要输入流对象,只需要输出流对象即可。输出流的前缀很容易判断:因为我们生成一个文件,所以此前缀为File,输出流的后缀不妨先设置为OutputStream,我们打算对其进行字节流的操作,所以调用了一下的方法:

byte[] bytes = str.getBytes();,因为要求输出流的构造参数需要为为字节类型的数据。

注意事项:根据需要确定是否需要输入流以及输出流。

/**
 * @author Fisherman
 */
public class MyTry {

    public static void main(String[] args) throws IOException {
        FileWriter fileWriter = new FileWriter("Mystr.txt");

		byte[] bytes = str.getBytes();

        FileOutputStream fileOutputStream = new FileOutputStream("Mystr.txt");

        fileOutputStream.write(bytes);

        fileOutputStream.close();

    }
}

 问题实际上就是确定2个前缀以及两个后缀,输出流的前缀很容易判断:因为我们生成一个文件,所以此前缀为File。输入流的后缀和输出流的前缀恰好是流的两端,一定要一致,这里先选择OutputStream,

当然我们也可以采用字符流的操作来进行,如下代码块:

/**
 * @author Fisherman
 */
public class MyTry {

    public static void main(String[] args) throws IOException {
        String str="hello world i am fisherman!!!!!1233";
        char[] chars =str.toCharArray();
        FileWriter fileWriter = new FileWriter("Mystr.txt");

        fileWriter.write(chars);
        fileWriter.close();

    }
}

注意事项:这里不要遗漏掉fileWriter的close方法,否则会造成文件写出失败。

  1. 将一个文件复制到另一个文件

对于文件的相关操作,推荐使用字节流,并且可以采用缓冲IO流进行包装:

无缓冲IO流的文件复制代码块:

 这里是两个文件的输入和输出,以及都是使用字节流,所以显然IO流对象采用的是:FileInputStream以及FileOutputStream。

/**
 * @author Fisherman
 */
public class CopyFIle {
    public static void main(String[] args) throws IOException {
        File inFile = new File("1.txt");
        File outFile = new File("2.txt");

        FileInputStream fins = new FileInputStream(inFile);

        FileOutputStream fouts = new FileOutputStream(outFile);

        int c ;

        while (((c = fins.read()) != -1)) {
            fouts.write(c);
        }

        fins.close();
        fouts.close();

    }
}

 由上面的代码我们可见其效率是比较低的,因为我们每次调用方法:fins.read()只能读取一个字节,然而频繁地访问硬盘上的资源是一个效率比较低的做法,所以需要使用缓冲IO流来对其进行装饰。

使用缓冲IO流进行装饰的代码块:

import java.io.*;

/**
 * @author Fisherman
 */
public class CopyFIle_Buffered {
    public static void main(String[] args) throws IOException {
        File inFile = new File("1.txt");
        File outFile = new File("2.txt");


        FileInputStream fins = new FileInputStream(inFile);

        FileOutputStream fouts = new FileOutputStream(outFile);

        BufferedInputStream bif = new BufferedInputStream(fins);

        BufferedOutputStream bof = new BufferedOutputStream(fouts);

        byte[] bytes = new byte[1024];//每次读取的最大数据量为1kb

        int length;

        while ((length = bif.read(bytes,0,1024))!=-1){
            bof.write(bytes,0,length);
        }

        bif.close();
        bof.close();

    }
}

三、总结

 Java的IO流操作实际上理解起来很容易,就简单确定输入、输出流的前缀以及后缀,前缀决定的是输入、输出类型,后缀决定read/write方法的参数类型。缓冲IO流我们大可将其视作一块具有能够优化数据所占内存空间大小的“智能”的内存。输出输出流的选择完全可以依靠本文所提到的两张图来完成选择。