> 文章列表 > 【JavaEE】文件操作(InputStream、OutputStream)

【JavaEE】文件操作(InputStream、OutputStream)

【JavaEE】文件操作(InputStream、OutputStream)

 

  • 博主简介:想进大厂的打工人
  • 博主主页:@xyk:
  • 所属专栏: JavaEE初阶 

在Java中总会用到文件操作,比如从盘符读写文件,按字节和字符进行数据读写,那么你真的认识什么是文件路径吗?平时谈到的“文件”,指的都是硬盘上的文件,文件IO这里也是操作硬盘了,本篇文章将详细讲解如何对文件系统操作,文件内容操作,文件操作需要用到的哪些API~~

JavaEE中的文件操作和IO,之前我们学习的代码,定义个变量,其实就是在内存上申请空间,Mysql中主要是操作硬盘的,文件IO也是操作硬盘!!

硬盘(外存)和内存相比:

速度:内存比硬盘快很多

空间:内存空间比硬盘小

成本:内存比硬盘贵

持久化:内存掉电后数据丢失,外存掉电后数据还在


目录

文章目录

一、认识文件

1.1 树型结构组织 和 目录

1.2 文件路径

二、文本文件vs二进制文件

三、文件系统操作

3.1 光看知识点,跟听天书一样,那么我来举个例子来理解吧:

4.1 文件内容操作

4.2 不带参数的read方法

4.3 write方法写数据

五、 文件查找内容程序练习

5.1 控制台输入要查询的目录和词

5.2 递归的进行目录/文件的遍历

5.3 文件读取

5.4 测试


一、认识文件

我们先来认识狭义上的文件(file)。针对硬盘这种持久化存储的I/O设备,当我们想要进行数据保存时,往往不是保存成一个整体,而是独立成一个个的单位进行保存,这个独立的单位就被抽象成文件的概念,就类似办公桌上的一份份真实的文件一般。

 文件除了有数据内容之外,还有一部分信息,例如文件名、文件类型、文件大小等并不作为文件的数据而存在,我们把这部分信息可以视为文件的元信息

 1.1 树型结构组织 和 目录

同时,随着文件越来越多,对文件的系统管理也被提上了日程,如何进行文件的组织呢,一种合乎自然的想法出现了,就是按照层级结构进行组织 —— 也就是我们数据结构中学习过的树形结构。这样,一种专门用来存放管理信息的特殊文件诞生了,也就是我们平时所谓文件夹(folder)或者目录(directory)的概念。

1.2 文件路径

这是文件系统上一个文件/目录,具体位置~

目录(专业术语)==文件夹(通俗的说法)

计算机的目录是由层级结构的

 可以看到,文件系统,是以树形结构来组织文件和目录的!!N叉树

文件路径:就是从树根节点出发,沿着树杈,一路往下走,到达目标文件,此时这中间经过的内容

Windows都是从“此电脑”起头的

表示路径的时候,可以把“此电脑” 省略,直接从 盘符 开始表示

C:\\javacode\\java-ee\\springDemo

 实际表示路径,是通过一个字符串表示,每个目录之间使用 \\ 或者 / 来分割

\\ 反斜杠 只是在windows中适用,代码中写需要写出 \\\\ ,需要转义字符的~

/ 斜杠 通常使用这种,推荐使用

从盘符开始,一层一层往下找,这个过程,得到的路径,叫做绝对路径

从给定的某个目录出发,一层一层往下找,这个过程得到的路径,叫做相对路径

一定要明确,基准目录(工作目录) 是什么!!!

假如工作目录是这个,此时找到

 

 相对路径表示,./JavaEE/springDemo

如果工作目录是

 要找到

 相对路径表示,../2.多线程(基础).md

. 相对路径中,是一个特殊符号,表示当前目录

..也是特殊符号,表示当前目录的上级目录~~

  • . . / . . / 代表上一级目录的上一级目录~

关于路径,非常关键~~

相对路径,一定要明确,工作目录是什么

相比之下,绝对路径,就可以理解成,以“此电脑”为工作路径

文件系统上,任何一个文件,对应的路径,是唯一的!!

不会存在,俩个路径相同,但是文件不同的情况!!

Windows上可以认为,路径和文件是一一对应的

路径就相当于一个文件的“身份标识”

二、文本文件vs二进制文件

文本文件,存储的是文本,文本文件的内容都是由ascii字符构成的

 对应ascii来说,表示范围0-127

文本文件里存储的数据,就是遵守ascii或者其他字符集编码,所得到的文件!!

本质上存的是字符

二进制文件存储的是二进制数据,则没有任何字符集的限制,存什么都行

简单粗暴的方式:

之间使用记事本来打开某个文件,如果你看到的内容能看懂,就是文本文件

看不懂,乱乱的,就是二进制文件(不仅仅是char类型)

txt,文本文件

.java / .c 也是文本文件

.class 二进制文件

.exe 二进制文件

jpg,MP3二进制文件

三、文件系统操作

Java 中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述。注意,有 File 对象,并不
代表真实存在该文件。
File对象是硬盘上的一个文件的“抽象”表示~~

文件是存储在硬盘上的,直接通过代码操作硬盘,不太方便

就在内存中创建一个对应的对象,操作这个内存中改的对象,就可以间接的影响到硬盘的文件情况了~~

构造File对象
我们先来看看 File 类中的构造方法和方法

构造方法

签名 说明
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 对象代表的文件是否是一个普通文件
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() 判断用户是否对文件有可写权限

3.1 光看知识点,跟听天书一样,那么我来举个例子来理解吧:

 

 IDEA工作路径就是项目所在目录

写相对路径,就是以

这一级为基准,来展开的~~ 

2.

 

exists() 判断 File 对象描述的文件是否真实存在
isDirectory() 判断 File 对象代表的文件是否是一个目录
isFile() 判断 File 对象代表的文件是否是一个普通文件

 3.

 

mkdir创建 File 对象代表的目录,mkdirs创建 File 对象代表的目录,如果必要,会创建中间目录

4.

 

list() 返回 File 对象代表的目录下的所有文件名
listFiles() 返回 File 对象代表的目录下的所有文件,以 File 对象
表示

5.

  

renameTo(File
dest)
进行文件改名,也可以视为我们平时的剪切、粘贴操

四、文件内容操作

4.1 文件内容操作

有很多类,一组类

针对文本文件,提供了一组类,统称为“字符流”(典型代表,Reader,Writer)读写的基本单位是字符

针对二进制文件,提供了一组类,统称为“字节流”(典型代表,InputStream,OutputStream)读写的基本单位是字节

每种流对象,又分成俩种,

输入的:Reader,InputStream

输出的:Writer,OutputStream

 InputStream 概述

抽象类,不能直接实例化!!! 

方法

修饰符及
返回值类
方法签名 说明
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() 关闭字节流

FileInputStream 概述

构造方法

签名 说明
FileInputStream(File file) 利用 File 构造文件输入流
FileInputStream(String name) 利用文件路径构造文件输入流

切记要进行,非常重要!!

文件这里的资源,需要手动释放!!

主要是“文件描述符”,记载了当前线程都打开了哪些文件~~

每次打开一个文件,就会在这个表里,申请到一个位置~

这个表就可以当作一个数组,数组下标就是文件描述符表,数组元素就是这个文件在内核中的结构体的表示~~

 之所以能这么写,是因为InputStream实现了一个特定的接口Closeable

try with resources

带有资源的try操作,会在try代码块结束,自动执行close关闭操作

OutputStream 概述
方法

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

4.2 不带参数的read方法

public static void main(String[] args) {try(InputStream inputStream = new FileInputStream("./123.txt")) {int b = 0;do {b = inputStream.read();System.out.println(b);}while(b != -1);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}
}

 

read读到末尾会返回-1

read和write可以一次读写多个字节,使用byte[]表示

4.3 write方法写数据

 

五、 文件查找内容程序练习

 5.1 控制台输入要查询的目录和词

public static void main(String[] args) {Scanner scanner = new Scanner(System.in);//1.先输入一个要搜索的目录System.out.println("请输入要搜索的根目录:");File rootDir = new File(scanner.next());if (!rootDir.isDirectory()){System.out.println("输入有误,您输入的目录不存在!");return;}//2.让用户输入一个要查询的词System.out.println("请输入要查询的词:");String word = scanner.next();//3.递归的进行目录/文件的遍历scanDir(rootDir,word);}
  1. 根据根目录构造File对象
  2. 如果这个file对象不是目录或者不存在的话,则说明输入错误,直接返回退出程序
  3. 如果是目录,输入要关键字
  4. 调用scanDir方法对目录进行扫描(自己实现)

5.2 递归的进行目录/文件的遍历

private static void scanDir(File rootDir, String word) {File[] files = rootDir.listFiles();if (files == null){//空目录return;}for (File f:files) {System.out.println("当前搜索到:" + f.getAbsolutePath());if (f.isFile()){//普通文件//打开文件,读取内容,比较关键词String content = readFile(f);if (content.contains(word)){System.out.println(f.getAbsolutePath()+"包含关键字");}}else if (f.isDirectory()){//是目录,进行递归scanDir(f,word);}else {continue;}}}

1.普通文件,打开文件,读取内容,比较关键词

2.是目录,进行递归

3.空目录退出

5.3 文件读取

private static String readFile(File f) {// 读取文件的整个内容, 返回出来.// 使用字符流来读取. 由于咱们匹配的是字符串, 此处只能按照字符流处理, 才是有意义的.StringBuilder stringBuilder = new StringBuilder();try (Reader reader = new FileReader(f)){while (true){int c = reader.read();if (c == -1){break;}stringBuilder.append((char)c);}} catch (IOException e) {e.printStackTrace();}return stringBuilder.toString();}

读取文件的整个内容, 返回出来.
使用字符流来读取. 由于咱们匹配的是字符串, 此处只能按照字符流处理, 才是有意义的.

5.4 测试