当前位置: 首页 > news >正文

【JavaEE】(4) 文件操作和IO

一、文件

        计算机中,文件保存在硬盘上,但是在程序中直接操作硬盘很复杂,操作系统就将硬盘封装成 “文件”,编程时,我们只需要操作打开文件、关闭文件、读文件、写文件等接口。操作系统通过文件管理器管理文件,所有文件构成一个 N 叉树结构:

所以可以通过文件路径描述一个文件的位置。对于每一级目录,windows 系统用 /(斜杠)、\(反斜杠)来划分;Linux、MacOS、Android 等用 / 划分。有相对路径绝对路径,相对路径是相对于基准路径./ 表示当前目录,../ 表示上一级目录。

二、文件的种类

  • 文本文件:存合法字符,数据的解析方式基于字符编码。

ascii:用数字表示英文字母、标点符号、阿拉伯数字。

后面引入更大的码表,表示汉字、俄语字符等。

gbk:2 个字符表示一个汉字。(windows 简体中文默认 gbk、VS 默认编码跟随系统)

utf-8(主流):utf-8 变长编码,2~4 个字节,一般汉字 3 个字节。

java 中一个 char 用到 utf-16(Unicode,定长) 是 2 个字符表示一个汉字,String 会在内部转为 utf-8 的形式。

  • 二进制文件:存什么都可以,比如图片、视频等。

三、文件操作

  • 文件系统操作:创建文件、删除文件、移动文件、获取文件属性等。
  • 文件内容操作:读文件、写文件。

1、File 类(文件系统操作)

  • 属性

pathSeparator :依赖系统的路径分隔符。

  • 构造函数

File(String pathname):pathname 是文件路径,相对或绝对。

File(String parent, String child):与基准路径拼接,字符串形式。

File(File parent,String child):与基准路径拼接,File 类形式。

对于开发工具来说,基准路径就是终端上显示的路径:

  • 方法

getParent():获取 File 的父目录

getName():获取 File 的文件名称

getPath():获取 File 的路径,看创建对象时的路径

getAbsolutePath():获取 File 的绝对路径,基准路径与相对路径单纯的拼接

getCanonicalPath():获取 File 的绝对路径,会去掉冗余的符号

绝对路径示例:

相对路径示例:

  • exists():File 文件是否真实存在。
  • isDirectory():判断 File 是否是一个目录。
  • isFile():判断 File 是否是一个普通文件。

  • createNewFile():创建文件,创建成功返回 true。
  • delete():删除成功返回 true。
  • deleteOnExit():程序结束后,才会删除。(就像编辑 word,会对修改内容保存一个隐藏文件,当 word 内存中内容保存到磁盘后,程序退出,隐藏文件才会删除)

  • list():列出目录下的所有文件名,返回的是 String[]
  • listFiles():列出目录下的所有文件,返回的是 File[]

  • mkdir():创建一层目录
  • mkdirs():创建多层目录

  • renameTo(File dest):文件改名移动

2、流对象(文件内容操作)

        读(输入)文件和写(输出)文件都是相对于 CPU 的,读文件:将数据从硬盘读到内存;写文件:将数据从内存写到硬盘。

        流对象主要分为两大类

  • 字节流:字节为单位读(InputStream)写(OutputStream),常用于读写二进制文件
  • 字符流:字符为单位读(Reader)写(Writer)(具体几个字节看编码方式,至少一个字节),常用于读写文本文件

PS:C/C++ 没有字符流的概念,只能按字节读取。如果想读取像汉字这样的多字节字符,那么首先得识别这个字符串的二进制序列使用的什么编码方式,然后判断从哪到哪是一个完整的汉字,最后在编码表中对应起来。

2.1、InputStream(字节流)

        InputStream 是个抽象类,不能创建实例,我们通过文件输入流 FileInputStream 创建实例(不仅文件有流得概念,网络等也有)。FileInputStream 会抛出 FileNotFoundException 异常。

        三种参数的 read 方法:会抛出 IOException 异常,而 IOException 是 FileNotFoundException 的父类

  • read():每次读取一个字节。读取成功返回 0~255 的整数;读取失败返回 -1

  • read(byte[] b):最多读取 b.length 个字节到 b(输出型参数) 中,返回读取到的字节数读取完毕则返回 -1(之所以设计 b 为输出型参数,是因为 java 只能有一个返回值,而已经有了返回值 n)。

  • read(byte[] b, int off, int len)从 off 位置开始,最多读取 len 个字节。
  • close():读取完毕后 ,需要关闭文件。进程的 PCB 中有一个文件描述符表(顺序表)的属性,它不能扩容。当程序一直运行,并打开文件却不关闭文件,那么表的空间就会耗尽。耗尽后再尝试打开,就会失败。这属于“文件资源泄露”。

        但是这样写还存在一个问题,比如下面这种写法,与上面的效果一样:

        将 close 写到 finally,无论以何种形式退出,都会执行 close:

        但是这样写代码就很丑,可读性降低,所以我们使用 try-with-resource 写法,会自动 close

2.2、OutputStream(字节流)

  • write(int b):写入一个字节。
  • write(byte[] b):写入一个字节数组。
  • write(byte[] b, int off, int len):写入一个字节数组的一部分。

        按 OutputStream 每次打开文件,都会清空文件内容。为了不清空,需要加上 append 参数为 true

2.3、Reader(字符流)

read 返回的是 0x00 ~ 0xff 的一个两字节整数,需要转换为 char

2.4、Writer(字符流)

3、案例练习

3.1、案例1

       扫描指定目录,找到所有包含指定字符的普通文件,并询问用户是否删除。

import java.io.File;
import java.io.IOException;
import java.util.Scanner;public class Demo10 {public static void main(String[] args) {// 1. 接收用户输入,指定目录文件名、字符串Scanner scanner = new Scanner(System.in);System.out.println("输入扫描的文件名:");String dirname = scanner.nextLine();System.out.println("输入删除的文件名包含的字符串:");String filestr = scanner.nextLine();// 2. 扫描目录文件File dir = new File(dirname);if(!dir.isDirectory()) {System.out.println("该目录不存在!");}scanDir(dir, filestr);scanner.close();}private static void scanDir(File dir, String filestr) {// 获得目录下的文件列表File[] files = dir.listFiles();// 判断文件列表是否为空if(files == null) {System.out.println("目录文件为空!");return;}// 遍历文件列表,删除包含字符串的普通文件for(File file : files) {String filename = file.getName();// 是一个普通文件,且文件名包含指定字符串,尝试删除文件if(file.isFile() && filename.contains(filestr)) {tryDeleteFile(file);// 是一个目录文件,递归扫描}else if(file.isDirectory()) {scanDir(file, filestr);}}}private static void tryDeleteFile(File file) {Scanner scanner = new Scanner(System.in);try {System.out.println("是否删除文件 " + file.getCanonicalPath() + "(Y or N):");} catch (IOException e) {e.printStackTrace();}String choice = scanner.nextLine();if(choice.equalsIgnoreCase("Y")) {if(file.delete()) {System.out.println("文件删除成功!");} else {System.out.println("文件删除失败!");}}scanner.close();}
}

3.2、案例2

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Scanner;public class Demo11 {public static void main(String[] args) {// 1. 接收用户输入,指定源文件、目标文件Scanner scanner = new Scanner(System.in);System.out.println("输入源文件路径:");String srcname = scanner.nextLine();System.out.println("输入目标文件路径:");String destname = scanner.nextLine();scanner.close();// 2. 判断源文件是否存在,目标文件的父目录是否存在File srcfile = new File(srcname);File destfile = new File(destname);if(!srcfile.isFile()) {System.out.println("源文件不存在!");return;}System.out.println(destfile.getParentFile());if(!destfile.getParentFile().isDirectory()) {System.out.println("目标文件的父目录不存在!");return;}// 3. 读取源文件内容,并写入目标文件copy(srcfile, destfile);}private static void copy(File srcfile, File destfile) {try (InputStream inputStream = new FileInputStream(srcfile);OutputStream outputStream = new FileOutputStream(destfile)) {byte[] bytes = new byte[1024];while(true) {int n = inputStream.read(bytes);if(n == -1) {break;}outputStream.write(bytes, 0, n);}} catch (IOException e) {e.printStackTrace();}}
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dtcms.com/a/258456.html

相关文章:

  • Ribbon负载均衡的具体实现原理
  • MyBatis Plus与P6Spy日志配置
  • OpenSIPS 邂逅 Kafka:构建高效 VoIP 消息处理架构
  • UAVAI-YOLO:无人机航拍图像的小目标检测模型
  • 深度优化OSS上传性能:多线程分片上传 vs 断点续传实战对比
  • ntext 数据类型不能选为 DISTINCT,因为它不可比
  • 解析云计算虚拟化基石:KVM、QEMU与Libvirt的协同
  • ✨从零搭建 Ubuntu22.04 + Python3.11 + PyTorch2.5.1 GPU Docker 镜像并上传 Docker Hub
  • C# WinForm跨平台串口通讯实现
  • RFID馆员工作站DW312-A|全国已经规模化应用
  • linux实时同步工具sersync
  • 利用 Python 脚本批量查找并删除指定 IP 的 AWS Lightsail 实例
  • FunASR搭建语音识别服务和VAD检测
  • 第23篇:OpenEuler 24.03系统下的备份与还原技术详解
  • 从牛顿流体到弹性固体:旋转流变仪的高精度流变特性测定与工业应用
  • WebRTC(九):JitterBuffer
  • web布局16
  • Android 开发问题:bluetoothLeScanner.startScan(scanCallback); 扫描不到设备
  • 使用 PyAEDT 设计参数化对数周期偶极子天线 LPDA
  • OSS与NAS混合云存储架构:非结构化数据统一管理实战
  • 【Java高频面试问题】数据库篇
  • Drag-and-Drop LLMs: Zero-Shot Prompt-to-Weights
  • Windows10的任务栏时间显示秒 笔记250624
  • vue3+echarts实现tab切换多个图表
  • redis的安装及操作
  • 数据库AICD特性之--一致性 Consistency
  • 大语言模型训练中的自监督学习和其他训练方式
  • 【技术难题】el-table的全局数据排序实现示例,不受分页影响,以及异步请求带来的页面渲染问题
  • 数据结构与算法:图论——深度优先搜索dfs
  • 数据结构知识点总结--绪论