IO流学习笔记

466 阅读16分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第18天,点击查看活动详情

1. File

1.1 概述

​ File对象主要是用来表示文件或者是目录的路径的。类中提供了很多对文件或者文件夹操作的常用方法。

1.2 创建对象

  • 绝对路径

    以磁盘名开头的路径。例如:D:\Program Files\Java\jdk1.8.0_172

    java中,路径的 \要用两个\\来表示,不然会被当成转义字符,无法正常显示

  • 相对路径

    不是以盘符开头的,相对于当前项目下的路径。例如: a.txt

    磁盘文件路径都是以\来分割路径的,如:D:\Program Files\Java\jdk1.8.0_172

    网络文件都是以/来分割路径的,如:r9tiho809.hn-bkt.clouddn.com/2022/04/11/…

创建文件的方法

//通过字符串类型的路径来创建对象
File(String pathname) 
     
//通过   父目录的路径(字符串类型)  和  文件(文件夹)名称   来创建对象
File(String parent, String child) 
    
//通过   父目录的路径(File类型)   和  文件(文件夹)名称   来创建对象
File(File parent, String child)

1.3 File类常用方法

boolean createNewFile()//根据路径创建一个文件,返回值代表创建是否成功
boolean mkdir() //根据路径创建一个文件夹,返回值代表创建是否成功
boolean mkdirs() //根据路径创建一个文件夹,如果父目录不存在会自动创建父目录

boolean exists() //判断文件或者文件夹是否存在
boolean isFile() //判断是否是一个文件
boolean isDirectory() //判断是否是一个文件夹
   
   一般要使用迭代删除操作
boolean delete() //删除文件,或者删除空文件夹,返回值代表删除是否成功

    
long length() //获取一个文件的大小,对文件夹无意义  单位是字节

String getName()//获取文件或文件夹的名字
File getParentFile() //获取父目录的File对象
String getAbsolutePath()//获取File对象的绝对路径   

1.4 重要方法

File[] listFiles() //如果当前File对象是一个文件夹,可以获取文件夹下的所有文件或者文件夹的File对象。

注意:如果不是文件夹或者是文件夹的权限受限返回值是null。所以一定要对返回结果做非空判断。

    public static void main(String[] args) {
        File dir = new File("C:\\Users\\root\\Desktop\\test\\a.txt");
        File[] files = dir.listFiles();
        if(files!=null){
            for (File file : files) {
                System.out.println(file);
            }
        }
    }

2.IO流

2.1 IO流概述

当需要进行数据的传输的时候可以使用IO流来进行。

例如:

  • 把磁盘中文件的数据读取到内存中。
  • 把内存中的数据写入到磁盘中。
  • 把网络中的数据读取到内存中。

文件读取进内存

数据写入到磁盘

2.2 IO流分类

​ IO流根据处理数据类型的不同分为字符流字节流,根据数据流向不同分为输入流输出流,对输入流只能进行读操作,对输出流只能进行写操作。

数据类型流向顶层父类
字节流输入(读)java.io.InputStream
字节流输出(写)java.io.OutputStream
字符流输入(读)java.io.Reader
字符流输出(写)java.io.Writer

3.字节流

3.1 字节输入流

所有字节输入流的父类是 java.io.InputStream ,它是以字节为单位的输入流 。

3.1.0 常用实现类FileInputStream

3.1.1 FileInputStream概述

FileInputStream是用来读取文件数据的字节输入流。

3.1.2 FileInputStream流对象创建

构造方法如下:

//传入文件路径创建对象
FileInputStream(String name) throws FileNotFoundException  

//传入文件路径的File对象来创建流对象
FileInputStream(File file) throws FileNotFoundException        

3.1.3 读取数据

可以使用FileInputStream来读取文件中的字节数据。

3.1.3.1 一次读取一个字节

核心方法如下:

// 读取一个字节的数据作为返回值返回  
public int read() throws IOException
// 返回值为-1时代表以及没有内容了

范例:

public static void main(String[] args) throws IOException {
    //  创建输入流对象
    FileInputStream fis = new FileInputStream("C:\\Users\\root\\Desktop\\test\\11.txt");
    //读取数据
    int b;
    while((b=fis.read())!=-1){
        System.out.println(b);
    }
    //释放资源
    fis.close();
}

操作完,要记得释放资源

3.1.3.2 一次读取一个字节数组

该方法常用

核心方法如下:

//传入一个字节数组,最多读取一个字节数组的数据,并且会把数据存入数组中,返回值代表本次读取到的有效字节的个数。   如果返回值为-1代表没有数据了
public int read(byte b[]) throws IOException 
// 如果返回值是-1,代表读到了末尾

范例:

    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("C:\\Users\\root\\Desktop\\test\\11.txt");
        //读取数据  一次读一个字节数组
        byte[] bytes = new byte[1024*2];
        int len;
        while ((len=fis.read(bytes))!= -1){
            System.out.println(new String(bytes,0,len));
        }
        //释放资源
        fis.close();
    }

3.1.3 资源释放问题

我们在前面处理异常的时候都同意做了声明抛出的处理。但是这很可能导致在出现了异常时资源没有被正确的释放。所以我们要更合理的处理异常,尤其是处理资源释放的问题。

3.2 字节输出流

3.2.0 常用实现类FileOutputStream

3.2.1 FileOutputStream概述

FileOutputStream是用来往文件中写入数据的字节输出流。

3.2.2 FileOutputStream流对象创建

常用构造方法如下:

FileOutputStream(String name) throws FileNotFoundException //传入文件路径创建对象
FileOutputStream(File file) throws FileNotFoundException    //传入文件路径的File对象来创建流对象

示例:

    public static void main(String[] args) throws FileNotFoundException {
        FileOutputStream fos = new FileOutputStream("C:\\Users\\root\\Desktop\\test\\11.txt");
        File file = new File("C:\\Users\\root\\Desktop\\test\\11.txt");
        FileOutputStream fos2 = new FileOutputStream(file);
    }

3.2.3 写数据

我们可以使用FileOutputStream来往文件中写入字节数据。

3.2.3.1 一次写一个字节

核心方法如下:

// 存入一个字节数组,把字节数组中的数据全部写入文件
public void write(byte b[]) throws IOException    

// 存入一个字节数组,把字节数组中从off索引开始len个元素写入文件
public void write(byte b[], int off, int len) throws IOException

范例:

    public static void main(String[] args) throws IOException {

        File file = new File("C:\\Users\\root\\Desktop\\test\\11.txt");
        FileOutputStream fos = new FileOutputStream(file);


        byte[] bytes = "abc".getBytes();
//        fos.write(bytes);
        fos.write(bytes,0,2);

        fos.close();
    }

3.2.3.2 一次写一个字节数组

核心方法如下:

// 存入一个字节数组,把字节数组中的数据全部写入文件
public void write(byte b[]) throws IOException   

// 存入一个字节数组,把字节数组中从off索引开始len个元素写入文件
public void write(byte b[], int off, int len) throws IOException  

范例:

    public static void main(String[] args) throws IOException {

        File file = new File("C:\\Users\\root\\Desktop\\test\\11.txt");
        FileOutputStream fos = new FileOutputStream(file);

		// 将字符串转换成byte数组
        byte[] bytes = "abc".getBytes();
//        fos.write(bytes);
        fos.write(bytes,0,2);

        fos.close();
    }

3.2.4 文件续写

如果用之前的构造方法创建的流对象,每次流对象创建的时候就会把文件中的内容情况。所以没有办法实现续写的效果。如果需要续写就需要使用另外的构造方法。

//第二个参数代表是否续写
FileOutputStream(String name, boolean append) throws FileNotFoundException 

 //第二个参数代表是否续写
FileOutputStream(File file, boolean append) throws FileNotFoundException 

​ 使用什么的构造创建流对象,并且第二个参数传入true,就不会清空文件中原有的内容。实现文件续写的效果。

范例:

    public static void main(String[] args) throws IOException {

        File file = new File("C:\\Users\\root\\Desktop\\test\\11.txt");
        FileOutputStream fos = new FileOutputStream(file,true);


        byte[] bytes = "abc".getBytes();
//        fos.write(bytes);
        fos.write(bytes,0,2);

        fos.close();
    }

3.3 字节流应用——文件复制

3.3.1 文件复制

​ 要求定义一个方法,该方法能够实现文件的复制

    public static void main(String[] args) throws IOException {
//        要求定义一个方法,该方法能够实现文件的复制
        // 文件的复制就是循环的读写,直到操作完所有数据为止
        
        // 源文件必须存在(不可自动创建)
        File src = new File("C:\\Users\\root\\Desktop\\test\\11.txt");
        // 若目标文件不存在则自动创建
        File destDir = new File("C:\\Users\\root\\Desktop\\test\\a");
        copyFile(src,destDir);
    }

    //源文件的路径  File srcFile
    //目标文件的存放目录路径  File destDir
    public static void copyFile(File srcFile,File destDir) throws IOException {
        //在destDir下创建一个和srcFile同名的文件
        File destFile = new File(destDir,srcFile.getName());
        //读取源文件  把读到的数据写入目标文件destFile
        FileInputStream fis = new FileInputStream(srcFile);
        FileOutputStream fos = new FileOutputStream(destFile);

        byte[] bytes = new byte[1024];
        int len;
        while((len=fis.read(bytes))!=-1){
            //把读到的内容写入新文件中
            fos.write(bytes,0,len);
        }
        //释放资源
        fis.close();
        fos.close();

    }

3.3.2 文件夹复制

要求定义一个方法,该方法能够实现文件夹的复制

public class Test09 {
    public static void main(String[] args) throws IOException {
        //要求定义一个方法,该方法能够实现文件夹的复制,考虑有子文件夹的情况
        File srcDir = new File("C:\\Users\\root\\Desktop\\test");
        File dest = new File("C:\\Users\\root\\Desktop\\test2");
        copyDir(srcDir,dest);
    }

    //File srcDir  源文件夹
    //File dest要复制到哪个目录
    public static void copyDir(File srcDir,File dest ) throws IOException {
        if(!(srcDir.exists()&&srcDir.isDirectory())){
            throw new RuntimeException("源文件夹必须存在并且是一个文件夹");
        }
        if(!dest.isDirectory()){
            throw new RuntimeException("目标文件夹必须是一个文件夹");
        }
        //1.在目标文件夹下创建一个和源文件夹同名的文件夹destDir
        File destDir = new File(dest,srcDir.getName());
        destDir.mkdirs();
        //2.获取源文件夹下的所有子文件
        File[] files = srcDir.listFiles();
        if(files!=null){
            //3.遍历数组,复制每一个文件到目标文件夹destDir下
            for (File file : files) {
                if(file.isFile()){
                    copyFile(file,destDir);
                }else {
                    //复制文件夹
                    copyDir(file,destDir);
                }

            }
        }

    }


    //源文件的路径  File srcFile
    //目标文件的存放目录路径  File destDir
    public static void copyFile(File srcFile,File destDir) throws IOException {
        //在destDir下创建一个和srcFile同名的文件
        File destFile = new File(destDir,srcFile.getName());
        //读取源文件  把读到的数据写入目标文件destFile
        FileInputStream fis = new FileInputStream(srcFile);
        FileOutputStream fos = new FileOutputStream(destFile);

        byte[] bytes = new byte[1024];
        int len;
        while((len=fis.read(bytes))!=-1){
            //把读到的内容写入新文件中
            fos.write(bytes,0,len);
        }
        //释放资源
        fis.close();
        fos.close();

    }
}

4. 编码表

4.1 编码表概述

4.2 常见的编码表

  • ASCII

    ​ 用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)

    ​ 基本的ASCII字符集,使用7位表示一个字符,共128字符。ASCII的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等

  • GBK

    ​ 最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等

  • Unicode

    ​ UTF-8编码:可以用来表示Unicode标准中任意字符,它是电子邮件、网页及其他存储或传送文字的应用 中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字节为每个字符编码

    ​ 编码规则:

    		128个US-ASCII字符,只需一个字节编码
    
    		拉丁文等字符,需要二个字节编码
    
    		大部分常用字(含中文),使用三个字节编码
    
    		其他极少使用的Unicode辅助字符,使用四字节编码
    
  • ANSI

    ​ 其实不是具体的编码表,它指代系统的默认编码表。例如:简体中文的Windows系统默认编码是GBK。

5. 字符流

​ 当需要读取/写入的数据是纯文本的形式时我们可以使用字符流来进行操作会更加方便。

(其内部其实也是字节流,不过就是字节流操作加上了编码表而已)

5.1 字符输入流

  • ​ 所有字符输入流的父类是 java.io.Reader ,它是以字符为单位的输入流 。
  • ​ 我们就以其子类FileReader为例进行学习。

5.1.0 常用子类FileReader

5.1.1 FileReader 概述

​ FileReader 是用来从文件中读取数据的字符输入流。

5.1.2 FileReader创建对象

构造方法如下:

//传入 文件路径 创建对象
public FileReader(String fileName) throws FileNotFoundException 

//传入 文件路径的File对象 来创建流对象 
public FileReader(File file) throws FileNotFoundException 

范例:

    public static void main(String[] args) throws FileNotFoundException {

        FileReader fr = new FileReader("C:\\Users\\root\\Desktop\\test\\汉字2.txt");

        FileReader fr2 = new FileReader(new File("C:\\Users\\root\\Desktop\\test\\汉字2.txt"));
    }

5.1.3 读取数据

5.1.3.1 一次读取一个字符

核心方法如下:

//一次读取一个字符返回,如果读到文件末尾,返回值为-1
public int read() throws IOException 
// 返回的int类型是指读到的字符的ASCLL码

范例:

    public static void main(String[] args) throws IOException {
        //创建流对象
        FileReader fr = new FileReader(new File("C:\\Users\\root\\Desktop\\test\\11.txt"));

        //调用方法
        int ch;
        while((ch=fr.read())!=-1){
            System.out.println((char)ch);
        }

        //释放资源
        fr.close();
    }

5.1.3.2 一次读取一个字符数组

核心方法如下:

//一次读取一个字符数组 返回值为-1时代表读到了末尾
public int read(char cbuf[]) throws IOException 
// 返回值是表示读取到的有效数值的个数

范例:

    public static void main(String[] args) throws IOException {

        //创建流对象
        FileReader fr = new FileReader(new File("C:\\Users\\root\\Desktop\\test\\11.txt"));

        //读取
        char[] chars = new char[1024];
        int len;
        while((len=fr.read(chars))!=-1){
            //说明读到了内容
            System.out.println(chars);
        }
        //释放资源
        fr.close();
    }

5.2 字符输出流

​ 所有字符输出流的父类是 java.io.Writer ,它是以字符为单位的输出流 。

​ 我们就以FileWriter为例进行学习。

5.2.0 常用类FileWriter

5.2.1 FileWriter概述

​ FileWriter是用来往文件写入数据的字符输出流。

5.2.2 FileWriter对象创建

构造方法如下:

//传入文件路径创建对象
public FileWriter(String fileName) throws IOException 

//传入文件路径的File对象来创建流对象
public FileWriter(File file) throws IOException     

范例:

    public static void main(String[] args) throws IOException {
        
        FileWriter fw = new FileWriter("C:\\Users\\root\\Desktop\\test\\11.txt");

        FileWriter fw2 = new FileWriter(new File("C:\\Users\\root\\Desktop\\test\\11.txt"));
    }

5.2.3 写入数据

5.2.3.1 一次写入一个字符

核心方法如下:

//把一个字符写入目的地
public void write(int c) throws IOException 

//把缓存区中的数据写入硬盘
public void flush() throws IOException 

范例:

public static void main(String[] args) throws IOException {

        //创建流对象  流对象一创建,里面内容会被清空掉fa
        FileWriter fw = new FileWriter(new File("C:\\Users\\root\\Desktop\\test\\11.txt"));

        //写数据
        fw.write('三');
        fw.write('更');
        fw.flush();
        fw.write('草');
        fw.write('堂');
        //释放资源
        fw.close();
    }
5.2.3.2 一次写入一个字符数组

核心方法如下:

//把一个字符数组写入目的地
public void write(char cbuf[]) throws IOException 

范例:

    public static void main(String[] args) throws IOException {

        //创建流对象
        FileWriter fw = new FileWriter(new File("C:\\Users\\root\\Desktop\\test\\11.txt"));

        //写数据
        char[] chars = "三更".toCharArray();
        fw.write(chars);

        fw.flush();

        chars = "草堂".toCharArray();
        fw.write(chars);

        //释放资源
        fw.close();
    }

5.3 字符流应用——文本文件复制

1.使用字符流实现纯文本文件的复制。

   public static void main(String[] args) throws IOException {
        //1.创建流对象
        File file = new File("C:\\Users\\root\\Desktop\\test\\11.txt");
        FileReader fr = new FileReader(file);
       
        // 该代码在执行时会判断该文件是否存在,没有就自动创建
        FileWriter fw = new FileWriter("C:\\Users\\root\\Desktop\\test\\22.txt");

        //2.循环读写
        char[] chars = new char[3];
        int len;
        while((len=fr.read(chars))!=-1){
            //把读到的内容写入新文件中
            fw.write(chars,0,len);
            //fw.flush();
        }

        //3.释放资源
        fw.close();
        fr.close();
    }

6.高效缓冲流

6.1 概述

​ 对硬盘进行数据的读取相比于从内存中存取数据要慢的多。所以JDK为我们提供了高效缓冲流来提高我们IO流的效率。内部原理就是借助内存的缓冲区来减少硬盘IO的次数,提高性能。

6.2 分类

  • 字节流

    • 输入流
      • BufferedInputStream
    • 输出流
      • BufferedOutputStream
  • 字符流

    • 输入流
      • BufferedReader
    • 输出流
      • BufferedWriter

    使用这些缓冲流对象就可以实现高效缓存

6.3 对象的创建

构造方法:

public BufferedInputStream(InputStream in) 
public BufferedOutputStream(OutputStream out)
public BufferedReader(Reader in) 
public BufferedWriter(Writer out)

范例:

    public static void main(String[] args) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\root\\Desktop\\test\\汉字.txt"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\root\\Desktop\\test\\汉字3.txt"));


        BufferedReader br = new BufferedReader(new FileReader("C:\\Users\\root\\Desktop\\test\\汉字3.txt"));

        BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\Users\\root\\Desktop\\test\\汉字3.txt"));
    }

6.4 特有的方法

方法作用
BufferedReaderpublic String readLine() throws IOException一次读取一行数据,读到的内容不包含换行符,读到了文件末尾返回null。
BufferedWriterpublic void newLine() throws IOException写入一个换行符,会根据系统变化

范例:

读取数据

    public static void main(String[] args) throws IOException {
        //readLine
        //创建对象
        BufferedReader br = new BufferedReader(new FileReader("C:\\Users\\root\\Desktop\\test\\333.txt"));

        //读取数据
        String line;
        while((line=br.readLine())!=null){
            //把读到的内容输出
            System.out.println(line);
        }
        
        //释放资源
        br.close();

    }

写入数据

    public static void main(String[] args) throws IOException {
        //newLine
        //创建对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\Users\\root\\Desktop\\test\\444.txt"));

        //写入数据
        bw.write("你好啊");
        //写入换号符
        bw.newLine();
        bw.write("我很好");
        //释放资源
        bw.close();
    }

循环写入数据

    public static void main(String[] args) throws IOException {
        //newLine
        //创建对象
        BufferedReader br = new BufferedReader(new FileReader("C:\\Users\\root\\Desktop\\test\\333.txt"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\Users\\root\\Desktop\\test\\444.txt"));

        //循环读写数据  把读到的数据写入目标文件中
        String line;
        while((line=br.readLine())!=null){
            //把读到的数据写入文件
            bw.write(line);
            //写入换行符
            bw.newLine();
        }

        //释放资源
        br.close();
        bw.close();
    }

6.5 应用场景

如果想让IO操作效率更高或者想使用特有的方法(readLine、newLine)就可以使用高效缓冲流。

7. 转换流

7.1 概述

如果我们需要把字节流转换成字符流,可以使用转换流来实现转换。

7.2 分类

流类型
输入流InputStreamReader
输出流OutputStreamWriter

7.3 转换流的使用

当我们需要把字节流转换成字符流时直接使用转换流的构造方法进行转换即可。

public InputStreamReader(InputStream in)
public InputStreamReader(InputStream in, String charsetName)
public OutputStreamWriter(OutputStream out)
public OutputStreamWriter(OutputStream out, String charsetName)

字节流 ---> 字符流

范例:

    public static void main(String[] args) throws FileNotFoundException {
        //字节流对象
        FileInputStream fis = new FileInputStream("C:\\Users\\root\\Desktop\\test\\汉字.txt");
        FileOutputStream fos = new FileOutputStream("C:\\Users\\root\\Desktop\\test\\转换流测试.txt");

        //转换成字符流
        InputStreamReader isr = new InputStreamReader(fis);
        OutputStreamWriter osw = new OutputStreamWriter(fos);
        
    }

8. Properties

​ Properties 其实是一个Map集合,其Key和Value都是String类型。他提供了和流结合的方法,可以方便我们把集合中的数据写入文件或者是把文件中的数据读取到集合中。

8.1 对象创建

构造方法:

public Properties() 

范例:

 public static void main(String[] args) {
	Properties properties = new Properties();  
 }

8.2 常用方法

Map集合的方法Properties都有,这里不做演示。因为我们在使用Properties的时候一般都是使用其特有的一些方法。

常用方法:

//设置键值对
public synchronized Object setProperty(String key, String value) 
    
//根据键获取对应的值    
public String getProperty(String key) 
    
//获取所有Key的集合
public Set<String> stringPropertyNames()

范例:

public static void main(String[] args) {
        Properties properties = new Properties();
        //存储key value
        properties.setProperty("name","三更");
        properties.setProperty("age","17");

        //获取对应的值
        String v = properties.getProperty("name");

        Set<String> keys = properties.stringPropertyNames();
        for (String key : keys) {
            String value = properties.getProperty(key);
            System.out.println(key+"===="+value);
        }
    }

8.3 和流结合的方法

//通过字符流加载数据
public synchronized void load(Reader reader) throws IOException  

//通过字节流加载数据
public synchronized void load(InputStream inStream) throws IOException  

//通过字符流保存数据
public void store(Writer writer, String comments) throws IOException 

//通过字节流保存数据
public void store(OutputStream out, String comments) throws IOException

范例:

    public static void main(String[] args) throws IOException {
        Properties pro = new Properties();
        //存数据
        pro.setProperty("name","三更");
        pro.setProperty("age","16");
        //把集合中的数据写入文件
        FileWriter fw = new FileWriter("C:\\Users\\root\\Desktop\\test\\proTest.txt");
        pro.store(fw,"java");
        fw.close();
    }
    public static void main(String[] args) throws IOException {
        //创建集合
        Properties pro = new Properties();
        //从文件中加载数据
        FileReader fr = new FileReader("C:\\Users\\root\\Desktop\\test\\proTest.txt");
        pro.load(fr);

    }

8.4 应用场景

Properties主要是用来读取和写入配置文件时使用。要求配置文件中的数据格式是: key=value

资料来源 www.bilibili.com/video/BV1hK…