Loading

Java IO相关使用

date: 2020-06-14 14:42:22
updated: 2020-08-21 17:35:45

Java IO相关使用

1. 文件

创建 File 对象的三种方式

  • 一个路径名:File(String pathname)
  • 一个父路径名和子路径名:File(File parent, String child)File(String parent, String child)
  • 一个URI (统一资源标识符):File(URI uri)

有文件时覆盖,无文件时创建。

通过 f.getAbsolutePath()f.getCanonicalPath() 可获取文件的绝对路径和规范路径

f.delete() 会立即删除文件,而 f.deleteOnExit() 会延迟删除,直到JVM调用该方法

File 对象不可变,始终表示文件的路径名。文件经过创建、删除后,File 对象依旧是原始的路径名,并不代表实际的文件。

2. 输入字节流

抽象基类是 InputStream 类,结构关系如下:

InputStream
|
+--FileInputStream
|
+--ByteArrayInputStream
|
+--PipedInputStream
|
+--FilterInputStream
|
+--BufferedInputStream
|
+--PushbackInputStream
|
+--DataInputStream
|
+--ObjectInputStream

基类的基本方法如下:

方法 描述
read() 读取一个字节并将读取的字节作为int返回。当到达输入流的结尾时,它返回-1。
read(byte[] buffer) 读取最大值直到指定缓冲区的长度。它返回在缓冲区中读取的字节数。如果到达输入流的结尾,则返回-1。
read(byte[] buffer,int offset, int length) 读取最大值到指定长度字节。数据从偏移索引开始写入缓冲区。它返回读取的字节数,如果到达输入流的结束它返回-1。
close() 关闭输入流
available() 返回可以从此输入流读取但不阻塞的估计字节数。

2.1 BufferedInputStream

通过缓冲数据向输入流添加功能。维护一个内部缓冲区以存储从底层输入流读取的字节。

import java.io.*;

public static void main(String[] args) throws IOException {
    String filePath = "/Users/mxxct/Desktop/md_meter.java";
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
    byte[] buffer = new byte[1024]; // 长度为1024个字节的缓冲区
    int len = -1; // 偏移量,或本次读取的字节数
    StringBuilder content = null;
    // 此次读取的字节数赋值给 len,如果等于 -1 说明已经读完了
    while((len = bis.read(buffer)) != -1){
        content.append(new String(buffer, 0, len));
    }
    System.out.println(content);
    bis.close();
}

3. 输出字节流

FileOutputStream fos = new FileOutputStream(destFile); 创建一个 FileOutputStream 对象,如果文件不存在,会尝试创建文件,但必须处理异常 FileNotFoundException,需要放在 try-catch 里面。

如果文件包含数据,数据会被覆盖。如果要追加,需要添加一个第二个参数,true 表示追加。

fos.write(int b)
fos.write(byte[] b)
fos.write(byte[] b, int off, int len)
由于输出的是字节流,所以只能 write int 或 byte[],如果是字符串的话,通过 getBytes() 方法可以返回字节数组

通过 fos.flush() 方法刷新输出流:将 write 里的字节缓存清出,写入到目标处。

4. 管道

管道IO基于生产者--消费者模式,PipedOutputStream 负责把数据写入到管道里,相当于生产者, PipedInputStream 负责读取管道里的数据

两种连接管道的方式

PipedInputStream pis  = new PipedInputStream(); 
PipedOutputStream pos  = new PipedOutputStream(); 
pis.connect(pos); /* Connect  the   two  ends */

PipedInputStream pis  = new PipedInputStream(); 
PipedOutputStream pos  = new PipedOutputStream(pis, 2048); // 缓冲区容量为2048字节
当创建管道时,可以设置管道容量。 如果管道的缓冲区已满,则尝试在管道上写入将会被阻止。

5. 字符输入流

Reader是所有的输入字符流的父类,它是一个抽象类
FilterReader是所有自定义具体装饰流的父类,其子类PushbackReader对Reader对象进行装饰,会增加一个行号
InputStreamReader是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream转变为Reader的方法。我们可以从这个类中得到一定的技巧。Reader中各个类的用途和使用方法基本和InputStream中的类使用一致。后面会有Reader与InputStream的对应关系。

BufferedReader reader = new BufferedReader(new FileReader(filePath));
String str;
while((str=reader.readLine())!=null){
    System.out.println(str);
}

6. 字符输出流

问:字节流与字符流有什么区别?
答:计算机中的一切最终都是以二进制字节形式存在的,对于我们经常操作的字符串,在写入时其实都是先将字符转成对应的字节,然后将字节写入到输出流,在读取时其实都是先读到的是字节,然后将字节直接使用或者转换为字符给我们使用。由于对于字节和字符两种操作的需求比较广泛,所以 Java 专门提供了字符流与字节流相关IO类。

对于程序运行的底层设备来说永远都只接受字节数据,所以当我们往设备写数据时无论是字节还是字符最终都是写的字节流。字符流是字节流的包装类,所以当我们将字符流向字节流转换时要注意编码问题(因为字符串转成字节数组的实质是转成该字符串的某种字节编码)。

字符流和字节流的使用非常相似,但是实际上字节流的操作不会经过缓冲区(内存)而是直接操作文本本身的,而字符流的操作会先经过缓冲区(内存)然后通过缓冲区再操作文件。

1、字节流在操作的时候本身是不会用到缓冲区(内存)的,是与文件本身直接操作的,而字符流在操作的时候是使用到缓冲区的

2、字节流在操作文件时,即使不关闭资源(close方法),文件也能输出,但是如果字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲区,并且可以使用flush方法强制进行刷新缓冲区,这时才能在不close的情况下输出内容

3、Reader类的read()方法返回类型为int :作为整数读取的字符(占两个字节共16位),范围在 0 到 65535 之间 (0x00-0xffff),如果已到达流的末尾,则返回 -1
inputStream的read()虽然也返回int,但由于此类是面向字节流的,一个字节占8个位,所以返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。因此对于不能用0-255来表示的值就得用字符流来读取!比如说汉字.

4、字节流与字符流主要的区别是他们的的处理方式

字节流:处理字节和字节数组或二进制对象;

字符流:处理字符、字符数组或字符串。

问:什么是缓冲区?有什么作用?

答:缓冲区就是一段特殊的内存区域,很多情况下当程序需要频繁地操作一个资源(如文件或数据库)则性能会很低,所以为了提升性能就可以将一部分数据暂时读写到缓存区,以后直接从此区域中读写数据即可,这样就显著提升了性能。
对于 Java 字符流的操作都是在缓冲区操作的,所以如果我们想在字符流操作中主动将缓冲区刷新到文件则可以使用 flush() 方法操作。

问:如何选择字节流和字符流?
答:如果是文本文件通常使用字符流,而像视频,图片,音频等文件都是二进制数据使用字节流。当然文本文件也可以使用字节流来操作,字节流更通用。

如果只是复制纯文本文件不做显示操作,哪个流都可以,如果要显示纯文本就用字符流。

问:为什么对于字符流中都有flush方法,但是字节流中没有?
字节流的操作不会经过缓冲区(内存)而是直接操作文本本身的,而字符流的操作会先经过缓冲区(内存)然后通过缓冲区再操作文件。

posted @ 2020-10-22 10:59  猫熊小才天  阅读(84)  评论(0编辑  收藏  举报