【Java】I/O 流篇 —— File 类与缓冲流

目录

  • File 类
    • File 类构造方法
    • 常见成员方法
      • 判断与获取
      • 创建与删除
      • 获取并遍历
  • 缓冲流
    • 字节缓冲流
      • 构造方法
      • 代码示例
      • 原理
    • 字符缓冲流
      • 构造方法
      • readLine()
      • newLine()
      • 缓冲区

File 类

  • File 对象表示一个路径,可以是文件的路径,也可以是文件夹的路径

  • 这个路径可以是存在的,也允许是不存在的

  • 绝对路径和相对路径的区别:

    • 绝对路径是指从根目录开始描述文件或目录位置的完整路径。无论你在系统中的哪个位置,使用绝对路径都能准确定位到目标资源。例如,在Windows操作系统中,C:\Users\username\Documents\example.txt 就是一个绝对路径;而在Linux或macOS系统中, /home/username/Documents/example.txt 则表示同样的含义。

    • 相对路径则是相对于当前工作目录的位置来描述文件或目录的路径。它不包含盘符(如 C:),也不一定从根目录开始。其有效性依赖于你所在的当前位置。比如如果你现在位于 D:\Projects 文件夹下,那么你可以用 .\myproject\src\main.cpp 来指代同级目录下的某个项目源码文件。

    • 简单来说:

      • 绝对路径总是能够唯一标识出一个具体的文件或文件夹,并且不会因为环境变化而改变;

      • 相对路径更短小精悍,但需要结合上下文理解,并随所在位置的不同会有差异。

File 类构造方法

  • public File(String pathname) 根据文件路径创建文件对象
  • public File(String parent,String child) 根据父路径名字符串和子路径名字符串创建文件对象(拼接)
  • public File(File parent,String child) 根据父路径对应文件对象和子路径名字符串创建文件对象(拼接)
import java.io.File;

public class FileDemo {
	public static void main(String[] args) {
		// 根据文件路径创建文件对象
		String str = "C:\\Users\\abcd\\Desktop\\输入输出.md";
		File f1 = new File(str);
		System.out.println(f1);
		
		// 根据父路径名字符串和子路径名字符串创建文件对象
		String parent = "C:\\Users\\abcd\\Desktop";
		String child = "输入输出.md";
		File f2 = new File(parent,child);
		System.out.println(f2);
		
		// 根据父路径对应文件对象和子路径名字符串创建文件对象
		File parent2 = new File("C:\\Users\\abcd\\Desktop");
		String child2 = "输入输出.md";
		File f3 = new File(parent2,child2);
		System.out.println(f3);
	}
}

常见成员方法

判断与获取

  • public boolean isDirectory() 判断此路径名表示的 File 是否为文件夹
  • public boolean isFile() 判断此路径名的 File 是否为文件
  • public boolean exists() 判断此路径名表示的 File 是否存在
  • public long length() 返回文件的大小(字节数量)
  • public String getAbsolutePath() 返回文件的绝对路径
  • public String getPath() 返回定义文件时使用的路径
  • public String getName() 返回文件的名称,带后缀
  • public long lastModified() 返回文件的最后修改时间(时间毫秒值)
import java.io.File;

public class FileOperations {
    public static void main(String[] args) {
        // 创建一个File对象,这里以项目根目录下的test.txt文件为例,可按需修改路径
        File file = new File("C:\\Users\\abcd\\Desktop\\输入输出.md");

        // 判断是否为文件夹
        boolean isDirectory = file.isDirectory();
        System.out.println("Is directory: " + isDirectory);

        // 判断是否为文件
        boolean isFile = file.isFile();
        System.out.println("Is file: " + isFile);

        // 判断是否存在
        boolean exists = file.exists();
        System.out.println("Exists: " + exists);

        // 获取文件大小(字节数),如果是文件夹此方法返回0
        long length = file.length();
        System.out.println("File size (bytes): " + length);

        // 获取绝对路径
        String absolutePath = file.getAbsolutePath();
        System.out.println("Absolute path: " + absolutePath);

        // 获取定义文件时使用的路径
        String path = file.getPath();
        System.out.println("Defined path: " + path);

        // 获取文件名称,带后缀
        String name = file.getName();
        System.out.println("File name: " + name);

        // 获取文件的最后修改时间(时间毫秒值)
        long lastModified = file.lastModified();
        System.out.println("Last modified time (milliseconds): " + lastModified);
    }
}

输出结果如下:

Is directory: false
Is file: true
Exists: true
File size (bytes): 4496
Absolute path: C:\Users\abcd\Desktop\输入输出.md
Defined path: C:\Users\abcd\Desktop\输入输出.md
File name: 输入输出.md
Last modified time (milliseconds): 1740232832244

创建与删除

  • public boolean createNewFile() 创建一个新的空的文件

  • public boolean mkdir() 创建单级文件夹

  • public boolean mkdirs 创建多级文件夹

  • public boolean delete() 删除文件、空文件夹(直接删除、不进入回收站)

import java.io.File;
import java.io.IOException;

public class FileCreateAndDeleteExample {
    public static void main(String[] args) {
        // 示例路径,可根据实际情况修改
        String filePath = "test.txt";
        String singleDirPath = "singleDir";
        String multiDirPath = "parentDir\\childDir";

        // 创建新文件
        File file = new File(filePath);
        try {
            if (file.createNewFile()) {
                System.out.println("文件 " + filePath + " 创建成功");
            } else {
                System.out.println("文件 " + filePath + " 已存在");
            }
        } catch (IOException e) {
            System.out.println("创建文件时出错: " + e.getMessage());
        }

        // 创建单级文件夹
        File singleDir = new File(singleDirPath);
        if (singleDir.mkdir()) {
            System.out.println("单级文件夹 " + singleDirPath + " 创建成功");
        } else {
            System.out.println("单级文件夹 " + singleDirPath + " 创建失败或已存在");
        }

        // 创建多级文件夹
        File multiDir = new File(multiDirPath);
        if (multiDir.mkdirs()) {
            System.out.println("多级文件夹 " + multiDirPath + " 创建成功");
        } else {
            System.out.println("多级文件夹 " + multiDirPath + " 创建失败或已存在");
        }

        // 删除文件
        if (file.delete()) {
            System.out.println("文件 " + filePath + " 删除成功");
        } else {
            System.out.println("文件 " + filePath + " 删除失败");
        }

        // 删除单级文件夹,注意:文件夹必须为空才能删除成功
        if (singleDir.delete()) {
            System.out.println("单级文件夹 " + singleDirPath + " 删除成功");
        } else {
            System.out.println("单级文件夹 " + singleDirPath + " 删除失败");
        }

        // 删除多级文件夹,同样要求各级文件夹为空
        if (multiDir.delete()) {
            System.out.println("多级文件夹 " + multiDirPath + " 删除成功");
        } else {
            System.out.println("多级文件夹 " + multiDirPath + " 删除失败");
        }
    }
}

注意事项

  • createNewFile():
    • 如果当前路径表示的文件原本是不存在的,则创建成功并返回 true
    • 如果当前路径表示的文件原本是存在的,则创建失败并返回 false
    • 如果父路径是不存在的,那么方法会有 IOException 异常
    • 创建的一定是文件,如果路径中不包含后缀名,则创建一个没有后缀的文件
  • mkdir():Windows 当中路径是唯一的,如果当前路径已经存在,则创建失败并返回 false
  • mkdir():既可以创建单级文件夹,又可以创建多级文件夹
  • delete():
    • 如果删除的是文件,直接删除,不进入回收站
    • 如果删除的是空文件夹,直接删除,不进入回收站
    • 如果删除的是有内容的文件夹,则删除失败

获取并遍历

  • public File[] listFiles() 获取当前该路径下所有内容
import java.io.File;

public class ListFilesExample {
    public static void main(String[] args) {
        // 指定要遍历的目录路径,可以根据需要修改
        File directory = new File("MyFiles");

        // 检查该 File 对象是否代表一个目录
        if (directory.isDirectory()) {
            // 调用 listFiles() 方法获取目录下的所有文件和子目录
            File[] files = directory.listFiles();

            // 检查返回的数组是否为空
            if (files != null) {
                // 遍历数组并输出每个文件或目录的名称
                for (File file : files) {
                    if (file.isDirectory()) {
                        System.out.println("目录: " + file.getName());
                    } else {
                        System.out.println("文件: " + file.getName());
                    }
                }
            } else {
                System.out.println("无法获取目录内容,可能发生 I/O 错误。");
            }
        } else {
            System.out.println("指定的路径不是一个目录。");
        }
    }
}

注意事项

  • 当调用者 File 表示的路径不存在时,返回 null
  • 当调用者 File 表示的路径是文件时,返回 null
  • 当调用者 File 表示的路径是一个空文件夹时,返回一个长度为 0 的数组
  • 当调用者 File 表示的路径是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在 File 数组中返回
  • 当调用者 File 表示的路径是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在 File 数组中返回,包含隐藏文件
  • 当调用者 File 表示的路径是需要权限才能访问的文件夹时,返回 null

缓冲流

字节缓冲流

字节缓冲流就是底层自带了缓冲区的字节流,提高了读取/写入的性能

构造方法

  • BufferedInputStream 字节缓冲输入流
    • public BufferedInputStream(InputStream is) 把基本流包装成高级流,提高读取数据的性能,缓冲区大小默认为 8129
    • public BufferedInputStream(InputStream is,int size) 把基本流包装成高级流,提高读取数据的性能,并指定缓冲区大小
  • BufferedOutputStream 字节缓冲输出流
    • public BufferedOutputStream(OutputStream os) 把基本流包装成高级流,提高写入数据的性能,缓冲区大小默认为 8129
    • public BufferedOutputStream(OutputStream os,int size) 把基本流包装成高级流,提高写入数据的性能,并指定缓冲区大小

代码示例

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo {
	public static void main(String[] args) throws IOException  {
		
		// 创建对象
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("aaa.txt"));
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bbb.txt"));
		
		// 复制数据
		int chr;
		while((chr = bis.read()) != -1) {
			bos.write(chr);
		}
		
		/* 
		 * byte[] bytes = new byte[1024];
		 * int len;
		 * while((len = bis.read(bytes)) != -1){
		 * 		bos.write(bytes,0,len);
		 * }
		 */
		
		// 释放资源
		bos.close();
		bis.close();
	}
}

原理

以下是原理图:

【Java】I/O 流篇 —— File 类与缓冲流_第1张图片

  1. 如果用的是空参 read 方法
    • 变量 ch 作为两个缓冲区之间的临时存储空间,一个字节一个字节的将数据从输入流的缓冲区传到输出流的缓冲区
  2. 如果用的是有参 read 方法
    • 字节数组 bytes 作为两个缓冲区之间的临时存储空间,将数组长度的字节数据从输入流的缓冲区传到输出流的缓冲区

字符缓冲流

字符缓冲流就是底层自带了缓冲区的字符流,提高了读取/写入的性能

构造方法

  • BufferedReader 字符缓冲输入流
    • BufferedReader(Reader r)
    • BufferedReader(Reader r,int size)
  • BufferedWriter 字符缓冲输出流
    • BufferedWriter(Writer w)
    • BufferedWriter(Writer w,int size)

readLine()

字符缓冲输入流的特有方法

public String readLine() 读取一行数据,如果没有数据可读,返回 null

代码示例

  1. 读取一行数据:

    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
    
    public class Demo {
    	public static void main(String[] args) throws IOException  {
    		
    		// 创建对象
    		BufferedReader br = new BufferedReader(new FileReader("aaa.txt"));
    		
    		// 读取数据
    		String line = br.readLine();
    		System.out.println(line);
    		
    		// 释放资源
    		br.close();
    	}
    }
    

    注意事项:readLine 方法一次读取一整行数据,遇到回车换行结束,但是不会把回车换行读取到内存当中

  2. 循环读取

    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
    
    public class Demo {
    	public static void main(String[] args) throws IOException  {
    		
    		// 创建对象
    		BufferedReader br = new BufferedReader(new FileReader("aaa.txt"));
    		
    		// 读取数据
    		String line;
    		while((line = br.readLine()) != null) {
    			System.out.println(line);
    		}
    		
    		// 释放资源
    		br.close();
    	}
    }
    

newLine()

字符缓冲输出流的特有方法:

public void newLine() 跨平台的换行

代码示例

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class Demo {
	public static void main(String[] args) throws IOException {
		// 创建对象
		BufferedWriter bw = new BufferedWriter(new FileWriter("bbb.txt"));
		
		// 写入数据
		bw.write("月色真美");
		bw.newLine();
		bw.write("跟你一样");
		
		// 释放资源
		bw.close();
	}
}

注意事项:如果要开追加模式(续写),true 应该加在 FileWriter 里面,因为 BufferedWriter 没有这个模式

缓冲区

虽然字节缓冲流和字符缓冲流的缓冲区长度都为 8192,但是字节缓冲流的是 8192 个字节,是 byte 类型的,占内存 8K,而字符缓冲流的是 8192 个字符,是 char 类型的,占内存 16K

你可能感兴趣的:(#,Java,基础,java,开发语言)