初识Java中的IO流

Java以流的形式处理数据的输入和输出。这些接口和类的定义被防放在java.io包下。

Java中IO流的体系

按照数据流动的方向,可以分为输入流和输出流,这里的输入/输出是以内存中的程序(进程)为基准的。按照流中数据的最小单位来分类,可以分为字节流和字符流。字节流适合操作所有类型的文件,而字符流只适合操作纯文本文件。

总的来说,如上图所示,Java的IO流分为四大类接口:字节输入流、字节输出流、字符输入流、字符输出流。这四个抽象类分别有对应的实现类。

注意IO流都实现了Closeable接口,这意味着其对象在使用完成之后都需要调用close()方法来关闭,即释放资源(也就是说IO流可以看作是一种资源)。实例化IO流对象和使用的过程中都可能会产生异常,在流对象正常关闭之前,如果因为异常而导致程序退出,则该流对象则无法被释放(事实上,所有资源都是如此)。因此,最好使用try-catch-finally语句块或try-with-resource语句块来让Java虚拟机自动管理资源的释放操作。

字节流FileInputStreamFileOutputStream

构造器提供了使用File对象或以字符串形式指定文件路径的两种构造器。其提供了读取和写入数据的接口,既可以每次只读/写一个字节,也可以使用字节数组作为缓冲每次读/写多个字节。一般来说使用缓冲数组读写效率更高(因为读写相同大小的数据时系统调用次数更少),缓冲数组越大,读写效率越高(不过效率增长并不是线性的)。

try (InputStream is = new FileInputStream("input/file/path");
     OutputStream os = new FileOutputStream("output/file/path")) {
    int len;
    byte[] buffer = new byte[1024];  // 缓冲数组的大小为1KB
    while ((len = is.read(buffer)) !=-1){
        os.write(buffer);
    }
    System.out.println("拷贝完成");
} catch (Exception e) {
    e.printStackTrace();
}

注意,这里的输出流对象只能对文件内容进行覆盖,如果要进行附加,可以在实例化时使用重载的另一个构造器,将append参数设置为true

字符流FileReaderFileWriter

try (Reader fr = new FileReader("input/file/path");
     Writer fw= new FileWriter("output/file/path")) {
    int len;
    char[] buffer = new char[10];
    while ((len = fr.read(buffer)) !=-1){
        fw.write(buffer, 0, len);
    }
    System.out.println("拷贝完成");
} catch (Exception e) {
    e.printStackTrace();
}

文件字符输出流在写文件时可以直接将字符串写入,这是针对字符型输出提供的接口。

注意,字符输出流写数据时会使用缓冲区,因此要让数据写到磁盘上的文件中,必须刷新流flush(关闭流时会自动进行刷新操作,因此关闭流也行)。在缓冲区装满时会自动进行刷新操作。

缓冲流

缓冲流这样的流类是对原始流的包装,以提高在某些功能上的性能和便利性。

缓冲流是为了提高流读写数据的性能,在磁盘和程序读写数据的字节数组之间,设置一定大小的缓冲区(在内存中,大小默认为8KB)。

try (InputStream bis = new BufferedInputStream(new FileInputStream("input/file/path"));
     OutputStream bos = new BufferedOutputStream(new FileOutputStream("output/file/path"))) {  // 在实例化时可以指定内部的缓冲区大小
    int len;
    byte[] buffer = new byte[1024];  // 缓冲字节数组大小为1024KB
    while ((len = bis.read(buffer)) != -1) {
        bos.write(buffer, 0, len);
    }
    System.out.println("拷贝成功");
} catch (Exception e) {
    e.printStackTrace();
}

一般来说,把缓冲流和缓冲字节数组结合使用(如上面所示),数据读写的效率更高。

上面的示例使用的是字节缓冲流,字符缓冲流BufferedReaderBufferedWriter的使用大体一致。BufferedReader提供了按行读取字符的接口public String readLine(),在没有数据可读时会返回nullBufferedWriter提供了换行(输出新行)的接口public void newLine(),在普通的字符输出流中,只能使用os.write("\r\n")来输出新行。

转换流

编码、字符集的问题在字符流读写时会出现,如果代码编码和被读取的文本文件的编码不一致,会出现乱码的问题。

为了解决这个问题,可以使用字符输入/输出转换流InputStreamReaderOutputStreamWriter。它先获取原始字节流,再按照字符集编码转成字符流。

Reader isr = new InputStreamReader(new FileInputStream("input/file/path", "GBK");
BufferedReader br = new BufferedReader(isr);

打印流

打印流可以实现更方便高效的打印数据。

PrintStream ps = new PrintStream("print/file/path");  // 打印到文件中
PrintStream ps1 = new PrintStream(System.out);  // 打印到控制台中

注意如果想要在文件后附加内容,需要在低级流对象实例化时指定append参数,再使用该对象去实例化高级流对象,而高级流对象并不能直接指定该参数。

打印流可以实现标准输出的重定向。

System.out.println("打印到控制台");
System.setOut(ps);  // 设置out重定向到文件中
System.out.println("打印到文件中");

数据流和序列化流

数据流DataInputStreamDataOutputStream将变量的类型和值一起读写到文件中。

序列化流ObjectInputStreamObjectOutputStream和数据流类似,只不过它是将Java的对象序列化/反序列化到文件中。要想对自定义对象进行序列化/反序列化操作,必须让类实现Serializable接口(这是一个标识接口,并没有任何抽象方法需要重写)。

IO框架

Java的框架一般是把类和接口等编译成字节码文件形式,压缩成一个.jar文件发行出去。Apache提供了Commons-io框架,封装了一组相关的IO操作。

这里学习一下如何在idea中添加第三方框架。

  1. 下载框架并解压,找到需要导入的jar文件。
  2. 在idea中找到自己的module,新建一个目录命名为lib,在该目录下把需要导入的文件复制进去。
  3. 右键单机该jar文件,并选择Add as Library
  4. 这样就可以在代码中导入包中的类了。
posted @ 2024-07-11 18:49  随机生成一个id  阅读(1)  评论(0编辑  收藏  举报