Java_IO流总结V1.0

一.File类

  1. 该类提供了对文件的创建、删除、查找等操作

  2. 构造方法

    构造方法方法说明
    File(String pathname)将路径字符串抽象为File实例,路径字符串可以是相对路径,也可以为绝对路径
    File(String parent, String child)从父路径名和子路径名来构建File实例
    File(File parent, String child)根据父File实例和子路径名来构建File实例
  3. 成员方法

    • 创建/删除

      创建、删除

      方法名方法说明
      boolean createNewFile() throws IOException当该名称的文件不存在时,创建一个由该抽象路径名的空文件并返回true,当文件存在时,返回false
      boolean mkdir()创建由此抽象路径名命名的目录
      boolean mkdirs()创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。级联创建目录
      boolean delete()删除由此抽象路径名表示的文件或目录

      上述方法比较简单,其中需要注意的是:

      • 创建多级目录时,mkdir创建失败,返回false,mkdirs创建成功,返回true(推荐使用mkdirs)
      • 删除目录时,目录内不为空时,删除失败,返回false, 即只能删除文件或者空目录
    • 获取

      方法名方法说明
      String getAbsolutePath()返回File对象的绝对路径字符串
      String getPath()将此抽象路径名转换为路径名字符串
      String getName()返回文件或目录的名称
      long length()返回由此File表示的文件的字节数
      String[] list()返回目录中的文件和目录的名称字符串数组
      File[] listFiles()返回目录中的文件和目录的File对象数组

      注意

      • length() 返回的是文件的字节数,目录的 长度是0
      • getPath()在用绝对路径表示的文件时相同,用相对路径表示的文件时不同
      • listFiles和list方法的调用,必须是实际存在的目录,否则返回null
      • listFiles和list 可以传入FilenameFilter的实现类,用于按照文件名称过滤文件
    • 判断

      方法名方法说明
      boolean isDirectory()判断是否是目录
      boolean isFile()判断是否是文件
      boolean exists()判断文件或目录是否存在
      boolean canWrite()文件是否可写
      boolean canRead()文件是否可读
      boolean canExecute()文件是否可执行
      long lastModified()返回文件的上次修改时间

      注意的是

      • 文件或目录不存在时, isDirectory() 或 isFile() 返回false
      • 可读、可写、可执行是对操作系统给文件赋予的权限

二.IO流

File类可以实现对文件的操作:创建、查找、删除文件,但是无法读取、传输文件中的内容。

IO流主要是读取、传输、写入数据内容的。

注意:

下面所说的输入流,输出流的主体是程序(即内存)

​ 程序将外部文件读入,称为输入流

​ 程序将数据写入文件,称为输出流

1.分类

  1. 按流向分:输入流

    ​ 输出流

  2. 按数据类型分:字节流

    ​ 字符流

  3. 按功能分:节点流

    ​ 处理流

    • 程序直接操作目标设备的类称为节点流
    • 对节点流进行装饰,功能、性能进行增强,称为处理流

2.1字节流

一切皆为字节

一切文件数据(文本、图片、视频等)在存储时,都是以二进制的形式保存,都可以通过使用字节流传输。

2.1.1 InputStream

  1. InputStream是字节输入流的顶层抽象

  2. 成员方法

    方法名方法说明
    int read() throws IOException;每次读取一个字节的数据,提升为int类型,读取到文件末尾时返回 -1
    int read(byte b[])throws IOException每次读取到字节数组中,返回读取到的有效字节个数,读取到末尾时返回 -1(常用)
    int read(byte b[], int off, int len)每次读取到字节数组中,从偏移量off开始,长度为len,返回读取到的有效字节个数,读取到末尾时返回 -1

2.1.2 OutputStream

OutputStream是字节输出流的顶层抽象

  1. 成员方法
方法名方法说明
void write(int b) throws IOException;将int值写入到输出流中
void write(byte[] b) throws IOException;将字节数组写入到输出流中
void write(byte b[], int off, int len) throws IOException将字节数组从偏移量off开始,写入len个长度到输出流中
void flush() throws IOException刷新输出流并强制缓冲的字节被写出

2.1.3 文件字节流

InputStream有很多的实现类,文件节点流是其中之一,即目标设备是文件,输入流和输出流对应的是FileInputStream和FileOutputStream

FileInputStream 文件字节输入流

  1. 构造方法

    public FileInputStream(File file) throws FileNotFoundException{}
    public FileInputStream(String name) throws FileNotFoundException{};
  2. 成员方法

    public int read() throws IOException从该输入流读取一个字节的数据
    public int read(byte[] b) throws IOException从该输入流读取最多b.length字节的数据到字节数组。
    public int read(byte[] b,int off, int len) throws IOException该输入流读取最多len字节的数据为字节数组。b:读取数据的缓冲区
    off:目标数组b的起始偏移量
    len:读取的最大字节数
  3. 如果用read()读取文件,每读取一个字节就要访问一次硬盘,这种效率较低。

  4. 如果用read(byte[])读取文件,一次读取多个字节,当文件很大时,也会频繁访问硬盘。如果一次读取超多字节,效率也不会高。

FileOutputStream 文件字节输出流

  1. 构造方法

    构造方法名方法说明
    FileOutputStream(File file) throws FileNotFoundException使用一个File对象来构建一个FileOutputStream
    FileInputStream(String name) throws FileNotFoundException使用一个文件名来构建一个FileOutputStream
    FileOutputStream(File file, boolean append) throws FileNotFoundExceptionappend传true时,会对文件进行追加
    FileOutputStream(String name, boolean append) throws FileNotFoundExceptionappend传true时,会对文件进行追加

    注意:

    • 上述构造方法执行后,如果file不存在,会自动创建该文件
    • 如果file存在,append没有传或者传了false,会清空文件的数据
    • 如果file存在,append传了true,不会清空文件的数据
  2. 开发中涉及文件的上传、下载、传输都是用的这个节点流,会结合装饰后的处理流一起使用

2.1.4内存节点流(了解)

ByteArrayInputStream是从内存的字节数组中读取数据

public ByteArrayInputStream(byte buf[]) {}

注意:不需要close数据源和抛出IOException,因为不涉及底层的系统调用

ByteArrayOutputStream是向内存字节数组中写数据,内部维护了一个数组

public ByteArrayOutputStream() {
   // 内部维护了一个可变的字节数组
   // protected byte buf[];
    this(32);
}

内存节点流代码示例

ByteArrayInputStream bis = new ByteArrayInputStream("data".getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int len = 0;
while ((len = bis.read()) != -1){
    bos.write(len);
}
// 输出data
System.out.println(new String(bos.toByteArray()));

应用场景

  1. 内存操作流一般在一些生成临时信息时会被使用,如果临时信息保存着文件中,代码执行完还要删除文件比较麻烦
  2. 结合对象流,可以实现对象和字节数组的互转

2.2 字符流

字符流封装了更加适合操作文本字符的方法

2.2.1 Reader 读取文本字符

  1. 成员方法

    方法名方法说明
    int read() throws IOException从输入流中读取一个字符,读到文件末尾时返回-1
    int read(char cbuf[]) throws IOException从输入流中读取字符到char数组中

2.2.2 writer 写出文本字符

  1. 成员方法

    方法名方法说明
    void write(int c) throws IOException写入单个字符到输出流中
    void write(char[] cbuf) throws IOException写入字符数组到输出流中
    void write(char[] cbuf, int off, int len) throws IOException写入字符数组的一部分,偏移量off开始,长度为len到输出流中
    void write(String str) throws IOException直接写入字符串到输出流中(常用)
    void write(String str, int off, int len) throws IOException写入字符串的一部分,偏移量off开始,长度为len
    Writer append(char c) throws IOException追加字符到输出流中

2.2.3 文件节点流

  1. FileReader

    FileReader主要是向磁盘文件中写出数据,常用构造方法如下

    public FileReader(String fileName) throws FileNotFoundException{}
    public FileReader(File file) throws FileNotFoundException {}
    

    注意:当读取的文件不存在时,会抛出FileNotFoundException,这点和FileInputStream一致

    1.read()循环读取文件

    FileReader fileReader = new FileReader("D:/三国/赵云.txt");
    int b;
    while ((b = fileReader.read()) != -1) {
        System.out.println((char) b);
    }
    

    2.read(char[]) 读取文件

    FileReader fileReader = new FileReader("D:/三国/赵云.txt");
    int len;
    char[] data = new char[2];
    while ((len = fileReader.read(data)) != -1) {
        System.out.println(new String(data, 0, len));
    }
    
  2. FileWriter

    FileWriter构造方法如下,和FileOutStream构造方法类似,和FileOutputStream类似。

    public FileWriter(String fileName) throws IOException {}
    
    public FileWriter(String fileName, boolean append) throws IOException {}
    
    public FileWriter(File file) throws IOException{}
    
    public FileWriter(File file, boolean append) throws IOException {}
    

    常用的写数据进文件的方法:

    FileWriter fileWriter = new FileWriter("D:/三国/孙权.txt");
    fileWriter.write(97); 
    fileWriter.write('b'); 
    fileWriter.write('C'); 
    fileWriter.write("权"); 
    fileWriter.append("力");
    

    注意:

    • 如果不执行close()或者flush()方法,数据只是保存到缓冲区,不会保存到文件。这点和与FileOutputStream不同

2.2.4 内存节点流(了解)

字符流也有对应的内存节点流,常用的有StringWriter和CharArrayWriter

StringWriter是向内部的StringBuffer对象写数据。

// 定义
public class StringWriter extends Writer {
    private StringBuffer buf;
    public StringWriter() {
        buf = new StringBuffer();
        lock = buf;
    }
}
// 应用
StringWriter sw = new StringWriter();
sw.write("hello");
StringBuffer buffer = sw.getBuffer();
// 输出hello
System.out.println(buffer.toString());

CharArrayWriter是向内部的char数组写数据

// 定义
public class CharArrayWriter extends Writer {
    protected char buf[];
}
// 应用 
CharArrayWriter caw = new CharArrayWriter();
caw.write("hello");
char[] chars = caw.toCharArray();
for (char c : chars) {
 // 输出了h e l l o
 System.out.println(c);
}

2.3 处理流

处理流是对节点流在功能上、性能上的增强

字符流的处理流的基类是FilterInputStreamFilterOutputStream

2.4 缓冲流

节点流,是直接使用操作系统底层方法读取硬盘中的数据,缓冲流是处理流的一种实现,增强了节点流的性能,为了提高效率,缓冲流类在初始化对象的时候,内部有一个缓冲数组,一次性从底层流中读取数据到数组中,程序中执行read()或者read(byte[])的时候,就直接从内存数组中读取数据。

分类

字节缓冲流:BufferedInputStream , BufferedOutputStream

字符缓冲流:BufferedReader , BufferedWriter

2.4.1字节缓冲流

可见构造方法传入的是节点流,是对节点流的装饰。

// 内部默认8192 =8*1024 即8M的缓冲区
public BufferedInputStream(InputStream in) {
   // 8192    
   // 内部维护了下面这样的字节数组
    // protected volatile byte buf[];
    this(in, DEFAULT_BUFFER_SIZE);
}
public BufferedOutputStream(OutputStream out) {
        this(out, 8192);
}

这里使用复制一部1G的电影来感受缓冲流的强大

1.使用基本的流读取数据(一次传输一个字节)

long start = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("D:/三国/视频.mp4");
FileOutputStream fos = new FileOutputStream("D:/三国/拷贝.mp4");
int data;
while ((data = fis.read()) != -1) {
    fos.write(data);
}
log.info("拷贝电影耗时:{}ms", System.currentTimeMillis() - start);
// 五分钟还没拷好,关闭程序了...

2.使用基本的流读取数据(一次传输一个8M的字节数组)

long start = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("D:/三国/视频.mp4");
FileOutputStream fos = new FileOutputStream("D:/三国/拷贝.mp4");
int len;
byte[] data = new byte[1024 * 1024 * 1024];
while ((len = fis.read(data)) != -1) {
    fos.write(data, 0, len);
}
log.info("拷贝电影耗时:{}ms", System.currentTimeMillis() - start);
// 拷贝电影耗时:4651ms

3.使用缓冲流读取数据(一次传输一个字节)

long start = System.currentTimeMillis();
BufferedInputStream fis = new BufferedInputStream(new FileInputStream("D:/三国/视频.mp4"));
BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream("D:/三国/拷贝.mp4"));
int data;
while ((data = fis.read()) != -1) {
    fos.write(data);
}
log.info("拷贝电影耗时:{}ms", System.currentTimeMillis() - start);
// 拷贝电影耗时:39033ms

4.使用缓冲流读取数据(一次传输一个8M的字节数组)(最常使用)

long start = System.currentTimeMillis();
BufferedInputStream fis = new BufferedInputStream(new FileInputStream("D:/三国/视频.mp4"));
BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream("D:/三国/拷贝.mp4"));
int len;
byte[] data = new byte[8 * 1024];
while ((len = fis.read(data)) != -1) {
    fos.write(data, 0, len);
}
log.info("拷贝电影耗时:{}ms", System.currentTimeMillis() - start);
// 拷贝电影耗时:1946ms

由上述四个例子可以得出结论,缓冲流读取数据比普通流读取数据快很多!

注意:采用边读边写的方式,一次传输几兆的数据效率比较高,如果采用先把文件的数据都读入内存,在进行写出,这样读写的次数是较小,但是占用太大的内存空间,一次读太大的数据也严重影响效率!

2.4.2字符缓冲流

对字符节点流的装饰,下面是字符缓冲流的构造方法

public BufferedReader(Reader in) {
 // private static int defaultCharBufferSize = 8192
 // 内部维护了一个字符数组
    // private char cb[];
    this(in, defaultCharBufferSize);
}
public BufferedWriter(Writer out) {
        this(out, defaultCharBufferSize);
}

字符缓冲流的特有方法:

方法名方法说明
BufferedReaderString readLine() throws IOException一行行读取,读取到最后一行返回null
BufferedWritervoid newLine() throws IOException写一个换行符到文件中,实现换行
// 创建流对象
BufferedReader br = new BufferedReader(new FileReader("D:/三国/赵云.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("D:/三国/赵子龙.txt"));
String line = null;
while ((line = br.readLine())!=null) {
  System.out.println(line);
  bw.write(line);
  bw.newLine();
}
// 结果
我乃常山赵子龙
于万军从中,取上将首级

2.4.3 缓冲流的正确姿势

缓冲流是IO流中最重要的知识点,下面通过代码实现正确用IO流的姿势:

BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
    bis = new BufferedInputStream(new FileInputStream(new File("D:/三国/视频.mp4")));
    bos = new BufferedOutputStream(new FileOutputStream(new File("D:/三国/拷贝.mp4")));
    int len;
    // 一次传输8M的文件,实际测试这里传输的大小并不影响传输的速度
    byte[] data = new byte[8 * 1024];
    while ((len = bis.read(data)) != -1) {
        bos.write(data, 0, len);
    }
} catch (IOException e) {
    log.error("error", e);
} finally {
   // finally块中关闭流,确保资源一定被关闭
    if (bis != null) {
        try {
            bis.close();
        } catch (IOException e) {
            log.error("error", e);
        }
    }
    if (bos != null) {
        try {
            bos.close();
        } catch (IOException e) {
            log.error("error", e);
        }
    }
}

2.5 关闭资源

方法名方法说明
void close() throws IOException流操作完毕后,必须释放系统资源,调用close方法,一般放在finally块中保证一定被执行!

注意:

  • 程序中打开的IO资源不属于内存资源,垃圾回收机制无法回收该资源,需要显式的关闭文件资源

三.IO流图解 V1.0

在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值