文件操作和 IO 全解析:从基础概念到 Java 实践

一、文件的基本认知

在计算机存储领域,文件是硬盘等持久化存储设备中独立的数据单位,如同办公桌上的一份份文档。每个文件不仅包含实际的数据内容,还有一系列描述信息,即文件元信息,像文件名、文件类型、文件大小、修改日期等,这些信息并非文件内容本身,却对文件管理至关重要。

二、文件的组织方式:树形结构与目录

随着文件数量增多,有序管理成为必然。树形结构因符合自然逻辑被广泛采用,由此诞生了专门用于管理文件的特殊 "文件"——目录(directory) 或文件夹(folder)

目录就像树形结构的节点,里面存储着文件的元信息,通过层层嵌套,形成了清晰的层级关系。例如 Windows 系统中,从 "此电脑" 开始,包含 "视频"“图片”“文档” 等子目录,子目录下又可包含更多文件和子目录;Linux 系统也有类似的树形结构组织。这种结构让文件的查找和管理变得高效且易于理解。

三、文件路径:定位文件的关键

要在文件系统中准确找到一个文件,就需要文件路径(Path),主要分为以下两种:

  • 绝对路径(absolute path):从树形结构的根节点开始,一直到目标文件的完整路径。例如C:\Windows\System32\cmd.exe,从 C 盘根目录出发,清晰指向了 cmd.exe 文件。
  • 相对路径(relative path):从任意节点(当前所在位置)出发到目标文件的路径。其中,.代表当前节点,..代表父节点。比如从C:\Program Files (x86)\WindowsPowerShell去往Windows NT,相对路径为..\Windows NT

不同操作系统的路径分隔符有所不同,Windows 常用\,而 Unix、Linux 等常用/

四、文件的分类与特性

1. 按数据类型划分

  • 文本文件:保存被字符集编码的文本,如 UTF-8 编码的中文文本,每个字符对应特定的字节序列。
  • 二进制文件:按照标准格式保存的非字符集编码数据,如 24 位位图文件,其数据以特定的二进制格式存储。

2. 文件扩展名

Windows 系统通过文件名中的后缀(扩展名)确定文件类型和默认打开程序,如.exe表示可执行程序,.dll表示动态库。但在 OSX、Unix、Linux 等系统中,并无此严格习俗。

3. 文件权限

操作系统会为不同用户赋予文件不同权限,通常包括可读、可写、可执行权限,以此保障数据安全。

4. 特殊文件

  • 快捷方式(Windows):对真实文件的引用,方便用户快速访问。
  • 软链接(Unix/Linux 等):类似快捷方式,可对同一文件建立多个引用。

此外,Unix、Linux 操作系统秉持 “万物皆文件” 理念,将所有 I/O 设备都抽象为文件,实现了接口的统一性。

五、Java 中的文件操作

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

1. File 类的核心内容

  • 属性:包含依赖于系统的路径分隔符,有String类型的pathSeparatorchar类型的pathSeparator
  • 构造方法
    • File(File parent, String child):根据父目录和子文件路径创建实例。
    • File(String pathname):根据文件路径(绝对或相对)创建实例。
    • File(String parent, String child):根据父目录路径和子文件路径创建实例。
  • 常用方法
    • 获取信息:getParent()(父目录路径)、getName()(文件名)、getPath()(文件路径)、getAbsolutePath()(绝对路径)、getCanonicalPath()(修饰过的绝对路径)等。
    • 判断状态:exists()(是否存在)、isDirectory()(是否为目录)、isFile()(是否为普通文件)等。
    • 操作文件:createNewFile()(创建空文件)、delete()(删除文件)、deleteOnExit()(JVM 结束时删除文件)等。
    • 操作目录:list()(目录下所有文件名)、listFiles()(目录下所有文件的 File 对象)、mkdir()(创建目录,中间目录不存在则失败)、mkdirs()(创建目录,必要时创建中间目录)等。
    • 其他:renameTo(File dest)(文件改名 / 剪切粘贴)、canRead()(是否可读)、canWrite()(是否可写)等。

2. 代码示例展示

  • 获取路径信息:通过getParent()getName()等方法可获取文件的各类路径相关信息。
  • 文件的创建与删除createNewFile()创建文件,delete()直接删除文件,deleteOnExit()则在程序运行结束后删除。
  • 目录的创建mkdir()创建单级目录,mkdirs()可创建多级目录。
  • 文件重命名renameTo()方法可实现文件的改名操作。
  • //示例 1:get 系列方法
    import java.io.File;
    import java.io.IOException;
    
    public class Main {
        public static void main(String[] args) throws IOException {
            File file = new File("..\\hello-world.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.getCanonicalPath());
        }
    }
    
     
    运行结果:
    ..
    hello-world.txt
    ..\hello-world.txt
    D:\代码练习\文件示例1\..\hello-world.txt
    D:\代码练习\hello-world.txt
    
  • //示例 2:普通文件的创建、删除
    import java.io.File;
    import java.io.IOException;
    
    public class Main {
        public static void main(String[] args) throws IOException {
            File file = new File("hello-world.txt"); // 要求该文件不存在
            System.out.println(file.exists());
            System.out.println(file.isDirectory());
            System.out.println(file.isFile());
            System.out.println(file.createNewFile());
            System.out.println(file.exists());
            System.out.println(file.isDirectory());
            System.out.println(file.isFile());
            System.out.println(file.createNewFile());
        }
    }
    
     
    //运行结果:
    false
    false
    false
    true
    true
    false
    true
    false
    
  • //示例 3:普通文件的删除
    import java.io.File;
    import java.io.IOException;
    
    public class Main {
        public static void main(String[] args) throws IOException {
            File file = new File("some-file.txt"); // 要求该文件不存在
            System.out.println(file.exists());
            System.out.println(file.createNewFile());
            System.out.println(file.exists());
            System.out.println(file.delete());
            System.out.println(file.exists());
        }
    }
    
     
    //运行结果:
    false
    true
    true
    true
    false
    
  • //示例 4:deleteOnExit 方法
    import java.io.File;
    import java.io.IOException;
    
    public class Main {
        public static void main(String[] args) throws IOException {
            File file = new File("some-file.txt"); // 要求该文件不存在
            System.out.println(file.exists());
            System.out.println(file.createNewFile());
            System.out.println(file.exists());
            file.deleteOnExit();
            System.out.println(file.exists());
        }
    }
    
     
    //运行结果:
    false
    true
    true
    true
    //程序运行结束后,文件会被删除。
    
  • //示例 5:目录的创建
    import java.io.File;
    import java.io.IOException;
    
    public class Main {
        public static void main(String[] args) throws IOException {
            File dir = new File("some-dir"); // 要求该目录不存在
            System.out.println(dir.isDirectory());
            System.out.println(dir.isFile());
            System.out.println(dir.mkdir());
            System.out.println(dir.isDirectory());
            System.out.println(dir.isFile());
        }
    }
    
    //运行结果:
    false
    false
    true
    true
    false
    
  • //示例 6:目录创建(mkdir 与 mkdirs 的区别)
    //使用mkdir()时,若中间目录不存在,则无法创建成功:
    import java.io.File;
    import java.io.IOException;
    
    public class Main {
        public static void main(String[] args) throws IOException {
            File dir = new File("some-parent\\some-dir"); // some-parent和some-dir不存在
            System.out.println(dir.isDirectory());
            System.out.println(dir.isFile());
            System.out.println(dir.mkdir());
            System.out.println(dir.isDirectory());
            System.out.println(dir.isFile());
        }
    }
    
    运行结果:
    false
    false
    false
    false
    false
    
     
    //使用mkdirs()可解决中间目录不存在的问题:
    import java.io.File;
    import java.io.IOException;
    
    public class Main {
        public static void main(String[] args) throws IOException {
            File dir = new File("some-parent\\some-dir"); // some-parent和some-dir不存在
            System.out.println(dir.isDirectory());
            System.out.println(dir.isFile());
            System.out.println(dir.mkdirs());
            System.out.println(dir.isDirectory());
            System.out.println(dir.isFile());
        }
    }
    
     
    运行结果:
    false
    false
    true
    true
    false
    
  • //示例 7:文件重命名
    import java.io.File;
    import java.io.IOException;
    
    public class Main {
        public static void main(String[] args) throws IOException {
            File file = new File("some-file.txt"); // 要求some-file.txt存在
            File dest = new File("dest.txt"); // 要求dest.txt不存在
            System.out.println(file.exists());
            System.out.println(dest.exists());
            System.out.println(file.renameTo(dest));
            System.out.println(file.exists());
            System.out.println(dest.exists());
        }
    }
    
    //运行结果:
    true
    false
    true
    false
    true

六、文件内容的读写:数据流

1. 输入流(InputStream)

  • 概述:用于读取数据,InputStream是抽象类,操作文件时常用其实现类FileInputStream
  • 主要方法
    • read():读取一个字节,返回 - 1 表示读完。
    • read(byte[] b):最多读取b.length字节到数组b,返回实际读取数量,-1 表示读完。
    • read(byte[] b, int off, int len):最多读取len - off字节到数组boff位置开始,返回实际读取数量,-1 表示读完。
    • close():关闭字节流。
  • 读取方式:可逐个字节读取,也可通过字节数组批量读取,后者 I/O 次数少,性能更好。对于字符读取,使用Scanner类更便捷,其Scanner(InputStream is, String charset)构造方法可指定字符集扫描读取。

2. 输出流(OutputStream)

  • 概述:用于写入数据,OutputStream是抽象类,操作文件时常用其实现类FileOutputStream
  • 主要方法
    • write(int b):写入一个字节。
    • write(byte[] b):将字节数组b的数据全部写入。
    • write(byte[] b, int off, int len):将字节数组b中从off开始的len个字节写入。
    • close():关闭字节流。
    • flush():将缓冲区数据刷入设备,因 I/O 速度慢,输出流通常先将数据写入缓冲区,需手动刷新。
  • 写入方式:可直接写入字节或字节数组,对于字符写入,可结合OutputStreamWriterPrintWriterPrintWriter提供了熟悉的print/println/printf方法,方便操作。

七、数据读写的常用模式

  • 按字节读:使用InputStream结合字节数组,循环读取直至结束。
  • 按字节写:使用OutputStream,将数据填入字节数组后写入,最后刷新缓冲区。
  • 按字符读:使用InputStream配合Scanner,按行读取字符内容。
  • 按字符写:使用OutputStreamOutputStreamWriterPrintWriter,按行写入字符内容,最后刷新。

掌握文件操作和 IO 是 Java 编程的重要基础,无论是简单的文件管理还是复杂的数据读写,都离不开这些核心知识和技能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值