Java 文件操作与IO流详解(File类 + 字节流 + 字符流全总结)

文章目录

一、文件的概念

狭义的文件 :保存在硬盘上的文件。
广义的文件:操作系统进行管理的一种机制,很多软件/硬件资源抽象成"文件"来进行表示。

注:当前这篇文章主要讨论狭义文件。

下面这张图片里面有一些文件,在计算机专业术语中称做:目录

一台计算机中能保存很多文件,区分/识别一个文件就需要通过文件的路径来进行识别。


二、路径

路径: 定位到文件的一系列过程。在计算机中目录套目录,形成了树形结构,从树根开始,到最终的文件,都需要经过哪些目录,把这些目录记录下来,就构成了路径。
斜杠 / : 在主流的操作系统中都是使用/来分割的。但是Windows是例外,Windows / 和 \(反斜杠 ) 都支持(Windows默认使用\)

2.1绝对路径

从根节点开始,逐级表示出来
示例:找E盘LX2下的test.txt文件的路径

绝对路为: E:\前端开发\实验二\LX2\test.txt


2.2相对路径

需要明确一个基准路径,以这个基准来找对应的文件。

示例:找E盘LX2下的test.txt文件的相对路径

假设基准为:E:\前端开发\实验二\LX2,那么test.txt的相对路径就是:./test.txt (.表示当前所在的目录位置)

假设基准为:E:\前端开发\实验二,那么test.txt的相对路径就是:./LX2/test.txt

假设基准为:E:\前端开发\实验二\LX2\photo,那么test.txt的相对路径就是:.../test.txt(..表示当前路径的上一层路径)


如果在代码中写一个相对路径,基准路径是谁呢?

不确定,取决于程序的运行方式,在IDEA中直接运行,基准路径就是项目的目录,如果打一个jar包,单独运行jar包,当前在哪个目录下执行运行命令(java -jar jar包名),基准目录就是哪个目录。

三、文件的种类

从开发的角度把文件分为两大类

  • 1.文本文件
  • 2.二进制文件
    在实际开发中判断一个文件是否是文本,最简单的方法是用记事本打开,打开之后不是乱码,能看懂文本,就是文本文件,如果是乱码,看不懂,就是二进制文件。
    示例:二进制文件 图片,音频,视频,可执行程序,word,docx 都是典型的二进制文件。
    示例:文本文件 txt纯文本, .java, .c都是典型的文本文件。

四、JAVA中操作文件

Java中通过java.io.File 类来对⼀个⽂件(包括目录)进行抽象的描述。注意,有File对象,并不代表真实存在该文件。

4.1 File类

File类是 Java 标准库(java.io 包)中定义的一个类。它用来表示文件或目录的路径,并提供操作这些路径的方法。

1. 属性表格

修饰符及类型 属性 说明
static String pathSeparator 依赖于系统的路径分隔符,String 类型的表示
static char pathSeparator 依赖于系统的路径分隔符,char 类型的表示

参数String文件的路径使用绝对路径/相对路径均可。

2. 构造方法表格

签名 说明
File(File parent, String child) 根据父目录 + 孩子文件路径,创建一个新的 File 实例
File(String pathname) 根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径
File(String parent, String child) 根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用路径表示

3. 方法表格

修饰符及返回值类型 方法签名 说明
String getParent() 返回 File 对象的父目录文件路径
String getName() 返回 File 对象的纯文件名称
String getPath() 返回 File 对象的文件路径
String getAbsolutePath() 返回 File 对象的绝对路径
String getCanonicalPath() 返回 File 对象的修饰过的绝对路径
boolean exists() 判断 File 对象描述的文件是否真实存在
boolean isDirectory() 判断 File 对象代表的文件是否是一个目录
boolean isFile() 判断 File 对象代表的文件是否是一个普通文件
boolean createNewFile() 根据 File 对象,自动创建一个空文件。成功创建后返回 true
boolean delete() 根据 File 对象,删除该文件。成功删除后返回 true
void deleteOnExit() 根据 File 对象,标注文件将被删除,删除动作会到 JVM 运行结束时才会进行
String[] list() 返回 File 对象代表的目录下的所有文件名
File[] listFiles() 返回 File 对象代表的目录下的所有文件,以 File 对象表示
boolean mkdir() 创建 File 对象代表的目录
boolean mkdirs() 创建 File 对象代表的目录,如果必要,会创建中间目录
boolean renameTo(File dest) 进行文件改名,也可以视为我们平时的剪切、粘贴操作
boolean canRead() 判断用户是否对文件有可读权限
boolean canWrite() 判断用户是否对文件有可写权限

4.2方法的使用

1.得到文件的基本信息操作

java 复制代码
package demo1;

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

public class Test {
    public static void main(String[] args) throws IOException {
        // 此处传入的是绝对路径,getPath得到的就是绝对路径
        File file = new File("E:/前端开发/实验二/LX2/test.txt");
        System.out.println("父目录文件路径: "+file.getParent());
        System.out.println("文件名称: "+file.getName());
        System.out.println("文件路径"+file.getPath());
        System.out.println("文件的绝对路径"+file.getAbsolutePath());
        // 简化了绝对路径中的 . 和 .. 
        System.out.println("简化过后的绝对路径"+file.getCanonicalFile());
    }
}

打印结果:

2.显示目录下的文件操作

java 复制代码
import java.io.File;
import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        File file = new File("E:/");
        //list 只是列出当前目录的子元素,无法列出子目录中的具体内容
        String[] list = file.list();
        System.out.println(Arrays.toString(list));
        System.out.println("================");
        // File 对象代表的目录下的所有文件,以 File 对象表示
        File[] list2 = file.listFiles();
        System.out.println(Arrays.toString(list2));
      
    }
}

打印结果:

3.创建目录

当前文件夹下为空,我们可以通过mkdir()创建目录

java 复制代码
public class Test {
    public static void main(String[] args) {
        File file = new File("E:/新建文件夹/text");
        System.out.println(file.mkdir());
    }
}

打印结果:

可以发现刚刚的文件夹下新建了一个名为text的目录


4.总结

1.文件是存储在硬盘上的。

2.目录也是文件,操作系统通过树形结构组织目录和文件的

3.通过路径定位到具体的文件

4.文件分为:文本文件和二进制文件


五、文件内容操作

JAVA中针对文件内容的操作,主要是通过一组流来实现的。

计算机中的流和水流非常相似:把数据看作连续不断的字节序列,就像水管里流动的水。

水流的特点:你可以用一桶接满(一次取100升),也可以用两个50升的桶分两次接,或者用10个10升的桶......总之,只要最终总量是100升,取水方式可以任意拆分。

文件流同理:计算机把文件内容视为一段连续字节流(byte stream)。读取时,你可以一次 read(100) 全读完,也可以循环10次、每次 read(10),甚至一次读1字节、读100次。只要每次读的大小之和等于100,并且按顺序读取,都能正确拿到全部数据。

因此,计算机中针对读写文件,也是使用流(Stream)。

5.1流的分类

流有几十种,可以分为两个类别:

  • 1.字节流:读写文件以字节为单位,是针对二进制文件使用的

InputStream 输入 从文件读数据

OutputStream 输出 往文件写数据

  • 2.字符流:读写文件以字符为单位,是针对文本文件使用的

Reader 输入

Writer 输出

输入输出是什么意思?

看数据的流向,从硬盘到CPU (输入),从CPU到硬盘(输出)

5.2 InputStream概述

1.方法

修饰符及返回值类型 方法签名 说明
int read() 读取一个字节的数据,返回 -1 代表已经完全读完了
int read(byte[] b) 最多读取 b.length 字节的数据到 b 中,返回实际读到的数据;-1 代表已经读完了
int read(byte[] b, int off, int len) 最多读取 len - off 字节的数据到 b 中,放在从 off 开始,返回实际读到的数据;-1 代表已经读完了
void close() 关闭字节流

2.使用

三个步骤:

1.打开文件

  1. 关闭

先创建一个名字为:text.txt的文件,内容为hello

java 复制代码
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class Test {
    public static void main(String[] args) throws IOException {
       // InputStream是抽象类,不能直接new
        // 创建对象成功就相当于去打开文件
        // try with resources 只要出现try代码块就会自动调用close
        try(InputStream inputStream = new FileInputStream("./text.txt")){
        while (true){
            int i = inputStream.read();
            if(i ==-1){
                break;
            }
            System.out.println(i);
        }
        }
    }
}

打印结果:hello这几个字母对应的ASCII表中的值


把text.txt中的文本内容改成:你好

如果文件中包含 非 ASCII 字符(如中文 "你"、"好"、表情符号等),这些字符在 UTF-8 编码下通常占多字节
一次读一个字节:

java 复制代码
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class Test {
    public static void main(String[] args) throws IOException {
       // InputStream是抽象类,不能直接new
        // 创建对象成功就相当于去打开文件
        // try with resources 只要出现try代码块就会自动调用close
        try(InputStream inputStream = new FileInputStream("./text.txt")){
        while (true){
        // 一次读一个字节
            int i = inputStream.read();
            if(i ==-1){
                break;
            }
            // 这里打印十六进制 一个十六进制数字是4个比特位,两个十六进制数字就是1一个字节,所以选择用十六进制来进行打印核对
            System.out.printf("%x\n",i);
        }
        }
    }
}

打印结果:

发现和上面的你好的UTF-8的码表对应上了。


一次读多个字节

java 复制代码
public class Test {
    public static void main(String[] args) throws IOException {
        try(InputStream inputStream = new FileInputStream("./text.txt")) {
            //一次读多个字节  数组的长度自行定义
            byte[] data = new byte[3];
            // 此处的读操作尽可能让数组填满,
            // 填不满的话,能填几个是几个
            while (true){
                // 此处的n是实际读到的字节数
                int n = inputStream.read(data);
                if(n == -1){
                    // 读完了
                    break;
                }
                for(int i = 0; i<n;i++){
                    System.out.printf("%x\n",data[i]);
                }
                System.out.println("===========");
            }
        }
    }
}

打印结果:一次读三个字节


5.3 OutputStream概述

1.方法

修饰符及返回值类型 方法签名 说明
void write(int b) 写入一个字节的数据
void write(byte[] b) 将 b 这个字节数组中的数据全部写入输出流中
void write(byte[] b, int off, int len) 将 b 这个字节数组中从 off 开始的数据写入输出流中,一共写 len 个
void close() 关闭字节流
void flush() 重要:我们知道 I/O 的速度是很慢的,所以,很多 OutputStream 为了减少设备操作的次数,在写数据的时候会先将数据暂时写入内存的一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写入设备中。这个区域一般称为缓冲区。但这会造成一个结果:我们写的数据很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置调用 flush()(刷新)操作,将数据刷到设备中。

这里的参数是int,主要是因为希望参数的取值范围为:0~255,因为JAVA中没有unsiged类型。


2.使用

示例:在output.txt文本文件中写入abc

首先这里面没有output.txt文本文件,等下我们可以观察是否新建了一个output.txt文本文件并写入abc

通过代码来实现

java 复制代码
import java.io.*;

public class Test {
    public static void main(String[] args)  {
       try(OutputStream outputStream = new FileOutputStream("output.txt")){
           outputStream.write(97);
           outputStream.write(98);
           outputStream.write(99);

       } catch (IOException e) {
           e.printStackTrace();
       }
    }
}

运行结果:新建了一个output.txt文本文件并写入了abc

对于OutputStream来说,如果文件不存在,会尝试创建文件并写入


OutputStream是会清处上一次的内容,打开文件的一瞬间,就被清除了

示例:把刚刚的output.txt中的acb改为大写的ABC

java 复制代码
import java.io.*;

public class Test {
    public static void main(String[] args)  {
       try(OutputStream outputStream = new FileOutputStream("output.txt")){
           byte[] bytes = {65,66,67};
           outputStream.write(bytes);

       } catch (IOException e) {
           e.printStackTrace();
       }
    }
}

运行结果


5.4Reader的使用


示例:
把text.txt文件中的abc读出来

java 复制代码
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class Test {
    public static void main(String[] args)  {
        try(Reader reader = new FileReader("text.txt")){
            while (true){
              int n =  reader.read();
              if(n == -1){
                  break;
              }
                System.out.println((char ) n);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

打印结果


5.5Writer的使用

将writer.txt中写入hello world

java 复制代码
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class Test {
    public static void main(String[] args) {
        try(Writer writer = new FileWriter("./writer.txt")){
             writer.write("hello world");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

打印结果


在原来的hello world 的基础上再追加写hello world

javapublic 复制代码
    public static void main(String[] args) {
        //追加再写一次hello world
        try(Writer writer = new FileWriter("./writer.txt",true)){
             writer.write("hello world ");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

打印结果


学习路上一起进步,如果觉得内容不错,记得点赞支持一下,也可以关注我,后续持续分享高质量技术文章!

相关推荐
派大星酷2 小时前
AOP 完整精讲:原理、核心概念、五种通知、切点语法、自定义注解实战
java·mysql·spring
七颗糖很甜2 小时前
预警!超级厄尔尼诺即将登场:2026-2027年全球气候或迎“极端狂暴模式”
java·大数据·python·算法·github
格林威2 小时前
面阵相机 vs 线阵相机:堡盟与Basler选型差异全解析 + Python实战演示
开发语言·网络·人工智能·python·数码相机·yolo·工业相机
小林望北2 小时前
Kotlin 协程:StateFlow 与 SharedFlow 深度解析
android·开发语言·kotlin
盐烟2 小时前
xpath-csv_doban_slider
开发语言·python
夫礼者2 小时前
【极简监控】挖出被遗忘的 JMX 金矿:用 Jolokia + Hawtio 把 VisualVM 搬进浏览器
java·监控·jolokia·jmx·hawtio
小学生-山海2 小时前
【安卓逆向】WE Learn登录接口iv、pwd参数分析,加密逆向分析
开发语言·python·安卓逆向
Slow菜鸟2 小时前
Java 开发环境安装指南(7) | Nginx 安装
java·开发语言·nginx
沐苏瑶2 小时前
Java反序列化漏洞
java·开发语言·网络安全