[Java EE] 文件操作(系统文件和字节流字符流)

一.文件操作

1.核心概念

文件 : 存储数据 ; 目录 : 存储文件/子目录的容器 ; Java 中均通过抽象类/接口表示

绝对路径 : 从根目录触发(如 D:/test/file.txt) ; 相对路径 : 从当前项目出发(如果再 IDEA 中直接运行 , 那么基准路径就是项目目录 ; 如果打了 jar 包 , 单独运行 jar 包 , 当前再哪个目录下执行运行命令的就是基准目录)

: 传统 IO 的核心 , 分为字节流(操作任意文件) 和 字符流(仅操作文本文件)

文本文件 : 数据以字符为基本 , 通过字符编码将字符映射为字节存储(能被记事本直接打开读懂) ; 二进制文件 : 以字节为单位 , 按一定格式存储(计算机可直接解析的原始字节流 , 用记事本打开为乱码)

 

2.Java 中操作系统文件

Java 中通过 java.io.file 类来对一个文件(包括目录)进行抽象描述 ;

注意 : 有 file 对象并不代表有真实文件存在

① 属性

静态常量

作用

示例(Windows/Linux)

File.separator

系统默认的「文件路径分隔符」

Windows:\ Linux:/

File.pathSeparator

系统默认的「路径列表分隔符」(如环境变量 PATH)

Windows:; Linux::

File.separatorChar

字符类型的路径分隔符(同 separator)

Windows:'\'Linux:'/'

File.pathSeparatorChar

字符类型的路径列表分隔符(同 pathSeparator)

Windows:';'Linux:':'

// 避免硬编码 "\\" 或 "/",用 separator 跨平台兼容
String path = "data" + File.separator + "test.txt"; 
System.out.println(path); 
// Windows 输出:data\test.txt;Linux 输出:data/test.txt

② 构造方法

方法名

说明

File(File parent, String child)

根据父目录 + 孩子文件路径,创建一个新的 File 实例

File(String pathname)

根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径

File(String parent, String child)

根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用路径表示

③ 常用方法 (基础)

返回值

方法签名

说明

String

getParent()

返回 File 对象的父目录文件路径

String

getName()

返回 File 对象的纯文件名称

String

getPath()

返回 File 对象的文件路径(构造方法传入绝对 / 相对路径,此方法就返回对应路径)

String

getAbsolutePath()

返回 File 对象的绝对路径(无论构造方法传相对 / 绝对路径,此方法都返回绝对路径)

String

getCanonicalPath()

返回 File 对象的修饰过的绝对路径(简化路径,把.//../等符号替代为实际路径)

boolean

exists()

判断 File 对象描述的文件是否真实存在

boolean

isDirectory()

判断 File 对象代表的文件是否是一个目录

boolean

isFile()

判断 File 对象代表的文件是否是一个普通文件

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

public class demo1 {
    public static void main(String[] args) throws IOException {
        //File file = new File("D:/JavaCode/src/FIle/demo.txt");//绝对路径
        //File file1 = new File("D:/JavaCode/src/FIle", "demo.txt");
        //File parent = new File("D/JavaCode/src/FIle");new File(parent, "demo.txt");
        File file2 = new File("./demo.txt");//相对路径
        System.out.println(file2.getParent());
        System.out.println(file2.getName());
        System.out.println(file2.getPath());
        System.out.println(file2.getAbsoluteFile());
        System.out.println(file2.getCanonicalFile());
        System.out.println(file2.exists());
        System.out.println(file2.isDirectory());
        System.out.println(file2.isFile());
    }
}

 

④ 常用方法

修饰符及返回值类型

方法签名

说明(含手写补充)

boolean

createNewFile()

根据 File 对象,自动创建一个空文件。成功创建后返回 true(注:需处理 IO 异常)

boolean

delete()

根据 File 对象,删除该文件。成功删除后返回 true

void

deleteOnExit()

根据 File 对象,标注文件将被删除,删除动作会到 JVM 运行结束时才会进行

String[]

list()

返回 File 对象代表的目录下的所有文件名

File[]

listFiles()

返回 File 对象代表的目录下的所有文件,以 File 对象表示(可以对 File 数组继续进行操作)

boolean

mkdir()

创建 File 对象代表的目录(make directory)

boolean

mkdirs()

创建 File 对象代表的目录,如果必要,会创建中间目录(创建多级目录)

boolean

renameTo(File dest)

进行文件改名,也可以视为我们平时的剪切、粘贴操作

boolean

canRead()

判断用户是否对文件有可读权限

boolean

canWrite()

判断用户是否对文件有可写权限

示例 1 : file1.createNewFile();

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

public class demo2 {
    public static void main(String[] args) throws InterruptedException {
        File file = new File("./demo3.java");
        file.deleteOnExit();
        Thread.sleep(1000);
    }
    public static void main1(String[] args) throws IOException {
        File file1 = new File("./text.txt");
        file1.createNewFile();
        System.out.println(file1.exists());
        System.out.println(file1.isFile());
        System.out.println(file1.isDirectory());
        //System.out.println(file1.delete());//若执行这行代码则文件消失
    }

 

示例 2 : 返回文件名

import java.io.File;
import java.util.Arrays;

public class demo4 {
    public static void main(String[] args) {
        File file = new File("d:/");
        String[] list = file.list();
        System.out.println(Arrays.toString(list));
        File[] files = file.listFiles();
        System.out.println(Arrays.toString(files));
    }
}

示例 3 : 创建目录

import java.io.File;

public class demo5 {
    public static void main(String[] args) {
        File file = new File("./test/1/2/3");
        Boolean a = file.mkdirs();
        System.out.println(a);//true,mkdirs() 能同时创建多级目录

        Boolean b = file.mkdir();
        System.out.println(b);//false,mkdir() 只能创建单级目录

    }
}

示例 4 : 剪切操作(需要执行上一个代码块)

import java.io.File;

public class demo6 {
    public static void main(String[] args) {
        File file = new File("./test");
        File file2 = new File("./src/test");
        boolean a = file.renameTo(file2);
        System.out.println(a);
    }
}

 

3.文件内容操作 -- 数据流

Java 文件内容操作 , 核心基类是四个抽象类(InputStream/OutputStream/Reader/Writer)
基类 ,对应 4 个常用文件实现类(FileInputStream/FileOutputStream/FileReader/FileWriter) , 共八个核心类 , 覆盖二进制文件读写和文本文件读写的所有场景

体系

抽象基类(2 个)

文件实现类(2 个)

核心用途

操作对象

字节流

InputStream(读)

FileInputStream

读取二进制文件(图片、视频、压缩包等)

字节(byte)

 

字节流

OutputStream(写)

FileOutputStream

写入二进制文件

字节(byte)

字符流

Reader(读)

FileReader

读取文本文件(.txt/.java 等)

字符(char)

字符流

Writer(写)

FileWriter

写入文本文件

字符(char)

 

4. 字节流 -- 操作二进制文件

4.1 抽象基类 InputStream (字节输入流)

InputStream 是所有字节输入流的父类 , 抽象类

核心方法 :

方法签名

作用

备注

int read()

读 1 个字节,返回字节值(0~255);读到末尾返回 -1

单字节读取,效率低

int read(byte[] buffer)

读多个字节到缓冲区,返回实际读取的字节数;末尾返回 -1

推荐!批量读取,效率高

int read(byte[] buffer,int off,int len)

len个字节到缓冲区,从 off

下标开始存储

精细控制读取范围

void close()

关闭流,释放资源

必须调用(建议用 try-with-resources 自动关闭)

long skip(long n)

跳过 n个字节不读

少用,适用于大文件跳转

 

4.2 文件实现类 FIleInputStream(文件字节输入流)

InputStream 的子类 , 专门用于从文件读取字节

构造方法 :

// 1. 传入文件路径(字符串)
InputStream in = new FileInputStream("D:/test.jpg");
// 2. 传入 File 对象
File file = new File("D:/test.jpg");
InputStream in = new FileInputStream(file);

示例 1 : 将文件完全读的两种方式

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

public class demo7 {
    public static void main(String[] args) throws IOException {
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream("./test.txt");
            while(true){
                int data = inputStream.read();
                if(data == -1){
                    break;
                }
                System.out.printf("0x%x ",data);
            }
        }
        finally {
            inputStream.close();
        }

    }
}

 

 

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

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

        try(InputStream inputStream = new FileInputStream("./test.txt")){
            //此处资源要求在try括号内直接声明并初始化, 并且使用括号将资源包裹起来, 避免出现异常时资源未关闭的情况
            while(true){
                byte[] data = new byte[1024];
                int n = inputStream.read(data);//返回读取的字节数
                System.out.println("n="+n);
                if(n == -1){
                    break;
                }
                for(int i = 0;i<n;i++){
                    System.out.print(data[i]+" ");
                }
                System.out.println();
            }
        }
    }
}

 


 

4.3 抽象基类 : OutputStream(字节输出流)

OutputStream 是所有字节输出流的父类 , 抽象类

核心方法 :

返回值类型

方法签名

说明

void

write(int b)

写入要给字节的数据

void

write(byte[] b)

将 b 这个字节数组中的数据全部写入输出流中

int

write(byte[] b, int off, int len)

将 b 这个字节数组中从 off 开始的数据写入输出流中,一共写 len 个

void

close()

关闭字节流

void

flush()

重要:I/O 速度较慢,多数 OutputStream 会先将数据写入缓冲区以减少设备操作次数;调用此方法可将缓冲区中残留的数据刷入设备,避免数据丢失

 

4.4 文件实现类 : FileOutputStream(文件字节输出流)

FileOutputStream 是 OutputStream 子类 , 用于向文件写入字节

构造方法 :

// 1. 覆盖写入(文件已存在则清空原有内容)
OutputStream out = new FileOutputStream("D:/test_copy.jpg");
// 2. 追加写入(文件已存在则在末尾添加内容)
OutputStream out = new FileOutputStream("D:/test_copy.jpg", true);
// 3. 传入 File 对象
File file = new File("D:/test_copy.jpg");
OutputStream out = new FileOutputStream(file, true);

示例 1 : 写入字节

import java.io.*;

public class demo9 {
    public static void main(String[] args) throws IOException {
        try(OutputStream outputStream = new FileOutputStream("./test.txt")){//如果不加true将会覆盖原文件内容
            //此处需要处理两个异常
            byte[] data = {88,66,85};
            outputStream.write(data);
        }
    }
    public static void main1(String[] args) throws IOException {
        try(OutputStream outputStream = new FileOutputStream("./test.txt",true)){
            //此处需要处理两个异常
            outputStream.write(78);
            outputStream.write(99);
            outputStream.write(79);
        }
    }
}

 

5. 字符流 -- 操作文本文件

5.1 抽象基类 : Reader(字符输入流)

Reader 是所有字符输入流的父类 , 抽象类

核心方法 :

方法签名

作用

备注

int read()

读 1 个字符,返回字符的 Unicode 码;末尾返回 -1

单字符读取,效率低

int read(char[] cbuf)

读多个字符到字符缓冲区,返回实际读取的字符数;末尾返回 -1

推荐!批量读取

int read(char[] cbuf, int off, int len)

len个字符到缓冲区,从 off

开始存储

精细控制读取范围

void close()

关闭流,释放资源

必须调用

 

5.2 文件实现类 : FileReader(文件字符输入流)

FileReader 是 Reader 的子类 , 用于文本文件读取字符(自动按系统默认编码)

构造方法 :

// 1. 传入文件路径
Reader reader = new FileReader("D:/test.txt");
// 2. 传入 File 对象
File file = new File("D:/test.txt");
Reader reader = new FileReader(file);

示例 1 : 将文件完全读的两种方式

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class demo10 {
    public static void main(String[] args) throws IOException {
        try(Reader reader = new FileReader("./test.txt")){
            while(true){
                char[] data = new char[1024];//缓冲区,也可以创建在循环外面重复使用
                int len = reader.read(data);//输出型参数
                //返回实际读取的字符个数,如果为-1表示已经读取完毕
                if(len == -1){
                    break;
                }
                for (int i = 0; i < len; i++) {
                    System.out.print(data[i]+" ");
                }
            }
        }
    }
    public static void main1(String[] args) throws IOException {
        try(Reader reader = new FileReader("./test.txt")){//这里要处理两个异常其中一个是IOException子类,另一个是IOException
            while(true){
                int data = reader.read();
                if(data == -1){
                    break;
                }
                System.out.printf("0x%x ",data);
            }
        }
    }
}

 

 

5.3 抽象基类 : Writer(字符输出流)

所有字符输出流的父类 , 是抽象类

核心方法 :

方法签名

作用

备注

void write(int c)

写 1 个字符(c是 Unicode 码)

单字符写入,效率低

void write(char[] cbuf)

把字符缓冲区的所有字符写入

批量写入,效率高

void write(char[] cbuf, int off, int len)

写入缓冲区从 off开始的 len个字符

精细控制写入范围

void write(String str)

直接写字符串(无需手动转字符数组)

最常用!文本文件写入首选

void write(String str, int off, int len)

写字符串从 off开始的 len个字符

截取字符串写入

void flush()

刷新缓冲区(字符流必须调用,否则数据可能未写入磁盘)

关键!避免数据丢失

void close()

关闭流(关闭前会自动刷新)

必须调用

 

5.4 文件实现类 : FileWriter(文件字符输出流)

FileWriter 是 Writer 的子类 , 用于向文本文件写入字符

构造方法 :

// 1. 覆盖写入
Writer writer = new FileWriter("D:/test.txt");
// 2. 追加写入
Writer writer = new FileWriter("D:/test.txt", true);
// 3. 传入 File 对象
File file = new File("D:/test.txt");
Writer writer = new FileWriter(file, true);

示例 1 : 写入字符

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class demo11 {
    public static void main(String[] args) throws IOException {
        try(Writer writer = new FileWriter("./test.txt",true)){
            char[] data = {'*','[',']','{'};
            writer.write(data);

        }
    }
}

6.字节流 vs 字符流:关键差异

对比维度

字节流(InputStream/OutputStream)

字符流(Reader/Writer)

操作单位

字节(byte

字符(char

编码依赖

无(直接操作原始字节)

有(自动编码 / 解码,需统一编码)

适用文件

所有文件(尤其是二进制文件:图片、视频、压缩包、.class)

仅文本文件(.txt/.java/.md/.csv 等)

核心方法

read(byte[])/write(byte[])

read(char[])/write(String)

缓冲区刷新

可选(flush()可省略)

必须(flush()否则数据可能滞留缓冲区)

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值