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

文件IO(Java)

注:此博文为本人学习过程中的笔记

1.概念

狭义上的文件是指保存在硬盘上的文件,广义上指操作系统进行资源管理的一种机制,很多软件/硬件资源都可以抽象成文件,这里我们针对的是狭义上的文件。

在硬盘里还有文件夹,这是通俗的说法,我们一般称其为目录。

2.硬盘,内存和寄存器

1.区别

存储空间

硬盘很大(几TB),内存更小(几十GB),寄存器非常小(不到1KB)

访问速度

硬盘很慢,内存快,寄存器很快

成本

硬盘便宜,内存贵,寄存器不单独卖,很贵

2.硬盘

硬盘分为固态硬盘和机械硬盘,机械硬盘受限于内部结构,速度非常慢。

3.路径

一台计算机中能够保存的文件有很多,那么要怎么识别唯一的文件呢?此时就需要用到路径。路径就是定位到文件的一系列过程。在计算机中,目录套目录形成了树形结构,从树根开始到最终的文件,都需要经过哪些目录,就形成路径。

1.使用

一般用“/”(正斜杠)表示。主流操作系统中都是使用/表示,windows比较特殊,使用“\”(反斜杠)表示。不过windows里是兼容正斜杠的,所以我们都使用正斜杠。在编写代码的时候,正斜杠可以直接使用,反斜杠需要转义。

2.相对路径和绝对路径

1.绝对路径

从盘符开始逐级表示

2.相对路径

相对路径需要明确一个基准,使用.表示基准的位置。使用..表示基准的上一层。使用../..表示基准的上两层。

在代码中写一个相对路径,它的基准是不确定的。如果在IDEA上运行,基准就是项目的目录。如果打一个jar包,单独运行jar包,那么是在哪个目录执行运行命令,基准就是哪个目录。

4.文件的种类

从开发的角度把文件分成两类,二进制文件和文本文件。图片,视频,压缩包之类的都是二进制文件。

所有的文件都是二进制文件,有一些文件是特殊的,二进制数据刚好能构成一些字符,能狗仔码表查到,并且构成有意义的内容。判断文本文件的方法很简单,直接用记事本打开看即可。注意word里的docx是二进制文件,里面不只有文本,还有格式,图表之类的东西。

5.Java标准库中操作文件的类

1.文件系统操作

创建文件,删除文件,重命名,创建目录

File - Java17中文文档 - API参考文档 - 全栈行动派 (qzxdp.cn)

进行文件系统操作时使用File这个类。里面的方法大多比较简单,查看文档即可,这里只写一些需要注意的点。

1.方法注意点

1.list()和listFile()

这个方法的作用是返回当前目录的子元素有哪些,需要注意的是它是无法获得子元素的子元素或孙子元素的,如果想,需要我们通过代码来实现。list返回的是字符串,而listFile返回的是File类,可以进行更多操作。

2.renameTo()

这个方法的作用是重命名目录,对于操作系统来说,重命名和移动本质上是一样的,因为定位文件是靠路径完成的。

2.文件内容操作

针对一个文件的内容进行读和写,通过一组“流对象”实现。流是操作系统层面的术语,和语言无关,其他语言操作文件内容也叫流。输入和输出是以cpu为参考的。

字节流读数据时是文件的原始数据。而字符流会根据文件内容的编码格式进行解析,比如可以把utf-8编码下3个字节的汉字解析后放到2个字节的char里。

其中的操作大部分是很相似的,这里就只详细介绍InputStream,其他都一笔带过。

1.字节流

读写文件以字节为单位,是针对二进制文件进行使用的。字节流主要有两个类InputStream和OutputStream,其他类都直接或间接继承这两个类。

1.InputStream
1.new操作
//注意InputStream是个抽象类
InputStream inputStream = new FileInputStream(文件路径);

这里的创建操作一旦成功,就认为打开了文件。要先打开文件才能进行操作,这是操作系统定义的流程。这个时候就不能忘记操作完成之后要关闭文件。

2.close()
inputStream.close();

不手动释放文件资源,就会引起文件资源泄露问题。 每次打开一个文件,就会在文件描述符表(固定长度的顺序表)中占据一个表项,如果光打开,不关闭,这里的文件描述符表的表项就会耗尽,后续再打开文件就会失败。文件操作附表是不能自动扩容的,操作系统内核里的操作是给所有进程提供的,如果能自动扩容会进一步增加内核的不可控因素。

close和unlock一样,容易因为各种原因漏掉,所以我们可以使用finally语句或者try语句的变种来保证close操作一定执行。

try {InputStream inputStream = new FileInputStream();
} finally {inputStream.close();
}//括号里可以new多个,在括号里new的东西会在try的代码块结束后自动调用close关闭
try(InputStream inputStream = new FileInputStream();) {}
//能自动关闭的类都实现了Closable接口
3.read() 

int read()

调用一次,读取一个字节,返回的是int而不是byte,返回值是正常数字时对照码表查具体是什么,返回-1是表示文件已经读完

try(InputStream inputStream = new FileInputStream("./text.txt")) {//开始进行读文件操作while(true) {int data = inputStream.read();if(data == -1) {//如果读完就退出break;}System.out.println(data);}
}

int read(byte[] b)

一次读若干个字节,读取到的数据放到参数b中。

这个方法使用参数作为方法的返回值。一般来说,方法都是把参数作为需要加工的材料,把返回值当作生产出来的产品。有时也会使用参数来接收返回值,当参数是一个引用类型时,方法内部修改对象内容也能影响到方法外部。

这种"输出型参数"本质上是语法的限制,因为语法限制方法只能有一个返回值,如果希望返回多个数据,只能通过参数来凑。

try(InputStream inputStream = new FileInputStream("./text.txt")) {byte[] data = new byte[1024];while(true) {//read方法会尽可能读完数据,直到把data填满为止。int n = inputStream.read(data);//这里的n表示实际读了几个字节for(int i = 0; i < n; i++) {System.out.println(data[i]);}}
}

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

这里的off表示offset指的是偏移量,也可以理解成数组下标,len表示长度。这个方法和第二个类似,多了指定下标和长度。

2.OutputStream

1.new

对于OutputStream来说,默认情况下会尝试创建不存在的文件。打开文件的一瞬间是会清除上次文件的内容的,可以设置成追加写的模式,避免文件被清空。

OutputStream outputStream = new FileOutputStream("./text.txt", true);
2.write

void write(int b)

一次写一个字节

void write(byte[] b)

一次写若干个字节

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

一次写若干个字节,可以指定下标和长度

2.字符流

读写文件以字符为单位,是针对文本文件进行使用的。字符流主要有两个类Writer和Reader,其他类都直接或间接继承这两个类。

1.Reader
1.read()

int read()

一次读一个字符

int read(char[] cbuf)

一次读一个字符数组

int read(CharBuffer target)

CharBuffer相当于对char[]进行了封装

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

一次读一个字符数组,可以指定下标和长度

2.Writer
write()

void write(int c)

void write(String str)

void write(char[] cubf)

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

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

3.提高效率的方法

1.手动创建缓冲区,手动减少read和write的次数

2.使用标准库提供的"BufferedStream"缓冲区流

相关文章:

  • 5.3 Dify:低代码平台,适用于企业快速部署合规AI应用
  • 自定义电池电量显示控件 BatteryView 实现
  • express的模板handlebars用app.engine()创建配置和用exphbs.create()的区别
  • Vue3后代组件多祖先通讯设计方案
  • MATLAB基础应用精讲-【基础知识篇】发布和共享 MATLAB 代码
  • ThinkPHP6模型中多组条件逻辑或Or查询的使用
  • BiliNote:开源的AI视频笔记生成工具,让知识提取与分享更高效——跨平台自动生成结构化笔记,实现从视频到Markdown的智能转化
  • Shell脚本-for循环应用案例
  • 算法训练营 Day1
  • OAuth2AuthorizationEndpointFilter类介绍、应用场景和示例代码
  • 第3讲、大模型如何理解和表示单词:词嵌入向量原理详解
  • Java面试高频问题(26-28)
  • AI新战局:Gemini 2.5 Pro强势挑战OpenAI o3,谁是真“全能”?“锯齿AGI”时代已来临?
  • 中国250米土壤质地类型数据
  • 筑牢数字防线:商城系统安全的多维守护策略
  • Ubuntu18.04更改时区(图文详解)
  • 【Python数据库与后端开发】从ORM到RESTful API
  • 前端基础之《Vue(11)—自定义指令》
  • 全栈国产化信创适配,构建安全可控的呼叫中心系统
  • 【安全扫描器原理】TCP/IP协议编程
  • 马上评丨市长信箱“已读乱回”,群众在意的是什么
  • 民航局:中方航空公司一季度运输国际旅客同比大增34%
  • 保时捷中国研发中心落户上海虹桥商务区,计划下半年投入运营
  • 四川甘孜州白玉县发生4.9级地震,震源深度10千米
  • 中方在IMF发声:美滥施关税威胁全球金融稳定,对新兴市场和发展中国家构成严峻挑战
  • 韩国京畿道骊州市市长率团访问菏泽:想和菏泽一起办牡丹节