目录🎐✨
1. 文件的概念
我们先来认识狭义上的文件(file)。针对硬盘这种持久化存储的I/O设备,当我们想要进行数据保存时,
往往不是保存成一个整体,而是独立成一个个的单位进行保存,这个独立的单位就被抽象成文件的概
念,就类似办公桌上的一份份真实的文件一般;
文件除了有数据内容之外,还有一部分信息,例如文件名、文件类型、文件大小等并不作为文件的数据
而存在,我们把这部分信息可以视为文件的元信息。
2. 目录 :树型结构组织
随着文件越来越多,对文件的组织就需要一种特殊的数据结构:
按照层级结构进行组织 —— 也就是数据结构中的树形结构。这样,一种专门用来存放管理信息的特殊文件诞生了,也就是我们平时所谓文件夹(folder)或者目录(directory)的概念。
3. 文件路径(Path)
3.1 绝对路径(absolute path)
从树型结构的角度来看,树中的每个结点都可以被一条从根开始,一直到达的结点的路径所描述,而这种描述方式就被称为文件的绝对路径(absolute path)。
3.2 相对路径(relative path)
除了可以从根开始进行路径的描述,我们可以从任意结点出发,进行路径的描述,而这种描述方式就被
称为相对路径(relative path),相对于当前所在结点的一条路径。
- 一个点表示当前节点
- 两个点表示父节点
4. 文本文件和二进制文件
即使是普通文件,根据其保存数据的不同,也经常被分为不同的类型,我们一般简单的划分为文本文件和二进制文件,分别指代保存被字符集编码的文本和按照标准格式保存的非被字符集编码过的文件。
Windows 操作系统上,有一类文件比较特殊,就是平时我们看到的快捷方式(shortcut),这种文件只是对真实文件的一种引用而已。其他操作系统上也有类似的概念,例如,软链接(soft link)等。
很多操作系统为了实现接口的统一性,将所有的 I/O 设备都抽象成了文件的概念,使用这一理念
最为知名的就是 Unix、Linux 操作系统 —— 万物皆文件。
5. Java 中的文件操作
Java 中通过 java.io.File
类来对一个文件(包括目录)进行抽象的描述。
注意,有 File 对象,并不代表真实存在该文件。
5.1 File 概述
File 类中的常见属性、构造方法和方法
属性:
构造方法:
方法:
5.2 代码示例
以D盘下的test.txt文件就行举列:
注意,使用相对路径时候的 . 时,代表的是当前项目所在的目录下
- file对象常用方法举列
package file;
import java.io.File;
import java.io.IOException;
public class Demo1 {
public static void main(String[] args) throws IOException {
File f=new File("d:\\test.txt");
System.out.println(f.getParent());//获取到文件的父目录
System.out.println(f.getName());//获取到文件名
System.out.println(f.getPath());//获取到文件路径(构造file的时候指定的路径)
System.out.println(f.getAbsolutePath());//获取到绝对路径
System.out.println(f.getCanonicalPath());//获取到绝对路径
System.out.println("==============");
File f2=new File("./test.txt"); //.代表的是当前项目所在的目录
System.out.println(f2.getParent());//获取到文件的父目录
System.out.println(f2.getName());//获取到文件名
System.out.println(f2.getPath());//获取到文件路径(构造file的时候指定的路径)
System.out.println(f.getAbsolutePath());//获取到绝对路径
System.out.println(f.getCanonicalPath());//获取到绝对路径
}
}
- 检查文件是目录文件还是普通文件
package file;
import java.io.File;
public class Demo2 {
public static void main(String[] args) {
File f=new File("./test.txt");
System.out.println(f.exists());
System.out.println(f.isDirectory());//文件是否是目录文件
System.out.println(f.isFile());//文件是否是普通文件
}
}
- 文件的创建和删除
package file;
import java.io.File;
import java.io.IOException;
public class Demo3 {
public static void main(String[] args) throws IOException {
//文件的创建和删除
File f=new File("./test.txt");
System.out.println(f.exists());
System.out.println("创建文件");
f.createNewFile();
System.out.println("创建文件结束");
System.out.println(f.exists());
}
}
package file;
import java.io.File;
public class Demo4 {
public static void main(String[] args) {
File f=new File("./test.txt");
f.delete();
}
}
执行次代码后项目路径下的test.txt被删除
- 创建多级目录
package file;
import java.io.File;
public class Demo5 {
public static void main(String[] args) {
//创建多级目录
File f=new File("./aaa/bbb/ccc/ddd");
f.mkdirs();
System.out.println(f.isDirectory());
}
}
执行后在当前文件夹下创建出多级目录:
**
**
- 遍历当前文件夹下的文件并输出
package file;
import java.io.File;
import java.util.Arrays;
public class Demo6 {
public static void main(String[] args) {
//遍历当前目录下的文件并输出
File f=new File("./");
System.out.println(Arrays.toString(f.listFiles()));
}
}
- 文件重命名
package file;
import java.io.File;
public class Demo7 {
//文件重命名
public static void main(String[] args) {
File f=new File("./aaa");
File f2=new File("./zzz");
f.renameTo(f2);
}
}
执行代码后将aaa文件夹重命名为zzz
6. 文件内容的读写 —— 数据流
6.1 InputStream 概述
方法:
注:InputStream
只是一个抽象类,要使用还需要具体的实现类。关于 InputStream
的实现类有很多,基本可以认为不同的输入设备都可以对应一个 InputStream
类,我们现在只关心从文件中读取,所以使
用 FileInputStream
6.2 FileInputStream 概述
构造方法:
6.3 OutputStream 概述
方法:
说明:OutputStream
同样只是一个抽象类,要使用还需要具体的实现类。我们现在还是只关心写入文件中,所以使用 FileOutputStream
6.4 利用PrintWriter 来对文件进行print写入
PrintWriter
类中提供了我们熟悉的 print/println/printf
方法
package file;
import java.io.*;
public class Demo16 {
public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
OutputStream os=new FileOutputStream("d:/test.txt");
OutputStreamWriter osWriter=new OutputStreamWriter(os,"utf-8");
PrintWriter writer=new PrintWriter(osWriter);
writer.print("hello");
writer.println("你好");
writer.printf("%d,%s\n",1,"没什么");
writer.flush();//刷新缓冲区
}
}
写入效果:
6.5 上述读写文件操作代码示例 :
- 读文件操作
package file;
import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class Demo8 {
//读文件操作
public static void main(String[] args) {
// 构造方法中需要指定打开文件的路径.
// 此处的路径可以是绝对路径, 也可以是相对路径, 还可以是 File 对象
/* InputStream inputStream=null;
try {
//1.创建对象,同时也是在打开文件
inputStream=new FileInputStream("d:/test.txt");
//2.尝试一个一个字节的读, 把整个文件都读完.
while (true){
int b=inputStream.read();
if (b==-1){
//读到了文件末尾
break;
}
System.out.print(b+" ");
}
}catch (IOException e){
e.printStackTrace();
}finally {
//3.读完之后记得关闭文件,释放资源
try {
inputStream.close();
}catch (IOException e){
e.printStackTrace();
}
}*/
//读完文件自动关闭文件的写法(一个一个的读)
try(InputStream inputStream=new FileInputStream("d:/test.txt")) {
while (true){
int b=inputStream.read();
if (b==-1){
break;
}
System.out.print(b+" ");
}
}catch (IOException e){
e.printStackTrace();
}
System.out.println();
//读完文件自动关闭文件的写法(一次性读取若干个字节)
try(InputStream inputStream=new FileInputStream("d:/test.txt")) {
while (true){
byte[] buffer=new byte[1024];
int len=inputStream.read(buffer);
if (len==-1){
//返回-1,读取完毕,break
break;
}
for (int i = 0; i < len; i++) {
System.out.print(buffer[i]+" ");
}
}
}catch (IOException e){
e.printStackTrace();
}
}
}
此时d盘下的test.txt文件中保存了abc三个字符
正确读取:
- 写文件操作
package file;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class Demo9 {
// 使用字节流, 写文件的案例(打开后会自动清空原来文件中保存的内容)
public static void main(String[] args) {
try(OutputStream outputStream=new FileOutputStream("d:/test.txt")) {
//outputStream.write(97);
//outputStream.write(98);
byte[] buffer=new byte[]{98,99,100};//bcd
outputStream.write(buffer);
}catch (IOException e){
e.printStackTrace();
}
}
}
执行代码后,文件被写成了 bcd
- 按照字符来读
package file;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
// 按照字符来读写
public class Demo10 {
public static void main(String[] args) {
//按照字符来读
try(Reader reader=new FileReader("d:/test.txt")) {
while (true){
char[] buffer=new char[1024];
int len=reader.read(buffer);
if (len == -1){
break;
}
for (int i = 0; i < len; i++) {
System.out.print(buffer[i]+" ");
}
System.out.println();//换行
// 如果这里传入的 数组 是 byte 数组, 还可以手动的指定一下 utf8 字符集避免乱码.
String s=new String(buffer,0,len);
System.out.println(s);
}
}catch (IOException e){
e.printStackTrace();
}
}
}
执行后成功读取d盘下的test.txt文件中的内容
- 按照字符来写
package file;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class Demo11 {
//按照字符来写 (如果要写的文件不存在,则自动创建文件)
public static void main(String[] args) {
try(Writer writer=new FileWriter("d:/test.txt")) {
writer.write("xyz");
}catch (IOException e){
e.printStackTrace();
}
}
}
执行后test.txt文件中的内容被成功写为xzy:
7. 利用 Scanner 进行字符读取
在项目文件中中新建好hello.txt,里面写 “你好!”;
package file;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;
public class Demo15 {
public static void main(String[] args) {
try(InputStream inputStream=new FileInputStream("hello.txt")) {
try(Scanner scanner=new Scanner(inputStream,"UTF-8")) {
while (scanner.hasNext()){
String s=scanner.next();
System.out.print(s);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
成功读取以“UTF-8”字符集编码方式读取 hello.txt 中的内容:
8. 利用上述读写操作实现小程序
8.1 小程序1
扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包含目录),并且后续询问用户是否要
删除该文件
package file;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
// 案例1, 实现查找文件并删除
public class Demo12 {
public static void main(String[] args) {
//1.先输入要扫描的目录,以及要删除的文件名
Scanner scanner=new Scanner(System.in);
System.out.println("请输入要扫描的文件路径:");
String rootDirPath=scanner.next();
System.out.println("请输入要删除的文件名:");
String toDeleteName=scanner.next();
File rootDir=new File(rootDirPath);
if (!rootDir.isDirectory()){
System.out.println("输入的扫描路径有误!");
return;
}
// 2. 遍历目录, 把 指定目录 中的所有文件和子目录都遍历一遍, 从而找到要删除的文件
// 通过这个方法来实现递归遍历并删除的操作
scanDir(rootDir,toDeleteName);
}
private static void scanDir(File rootDir, String toDeleteName) {
//1.先列出rootDir中的所有内容
File[] files=rootDir.listFiles();
if (files==null){
//rootDir是一个空目录
return;
}
// 2. 遍历当前列出的这些内容. 如果是普通文件, 就检测文件名是否是要删除的文件.
// 如果是目录, 就递归的进行遍历
for (File f:files){
if (f.isFile()){
//普通文件的情况
if (f.getName().contains(toDeleteName)){
// 不要求名字完全一样, 只要文件名中包含了关键字即可删除
// 就进行删除操作
deleteFile(f);
}else if (f.isDirectory()){
//目录就进行递归遍历
scanDir(f,toDeleteName);
}
}
}
}
private static void deleteFile(File f) {
try {
System.out.println(f.getCanonicalPath()+"确认要删除吗?(Y/N)");
Scanner scanner=new Scanner(System.in);
String choice=scanner.next();
if (choice.equals("Y") || choice.equals("y")){
f.delete();
System.out.println("文件删除成功!");
}else {
System.out.println("文件取消删除!");
}
}catch (IOException e){
e.printStackTrace();
}
}
}
运行效果:
执行代码后,位于当前项目目录下(.)的hello.txt文件被成功删除!
8.2 进行普通文件的复制
package file;
import java.io.*;
import java.util.Scanner;
public class Demo13 {
//进行普通文件的复制
public static void main(String[] args) {
//1.输入两个路径
Scanner scanner=new Scanner(System.in);
System.out.println("请输入要拷贝的源路径:");
String src=scanner.next();
System.out.println("请输入要拷贝的目标路径");
String dest=scanner.next();
File srcFile=new File(src);
if (!srcFile.isFile()){
System.out.println("输入路径有误!");
return;
}
// 此处不太需要检查目标文件是否存在. OutputStream 写文件的时候能够自动创建不存在的文件.
// 2. 读取源文件, 拷贝到目标文件中
try(InputStream inputStream=new FileInputStream(src)) {
try(OutputStream outputStream=new FileOutputStream(dest)){
// 把 inputStream 中的数据读出来, 写入到 outputStream 中
byte[] buffer=new byte[1024];
while (true){
int len=inputStream.read(buffer);
if (len==-1){
//读取完毕
break;
}
// 写入的时候, 不能把整个 buffer 都写进去. 毕竟 buffer 可能是只有一部分才是有效数据.
outputStream.write(buffer,0,len);
}
}
}catch (IOException e){
e.printStackTrace();
}
}
}
运行:
执行代码后,成功将项目目录下的copy.txt文件中的(aaa)复制到d盘下的copy2文件中
8.3 扫描指定目录,并找到名称或者内容中包含指定字符的所有普通文件(不包含目录)
注意:此方案性能较差,所以尽量不要在太复杂的目录下或者大文件下实验
package file;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Scanner;
public class Demo14 {
// 扫描指定目录,并找到名称或者内容中包含指定字符的所有普通文件(不包含目录)
public static void main(String[] args) throws IOException {
//1.输入要扫描的文件路径
Scanner scanner=new Scanner(System.in);
System.out.println("请输入要扫描的文件路径:");
String rootDirPath=scanner.next();
System.out.println("请输入要查询的关键字:");
String word=scanner.next();
File rootDir=new File(rootDirPath);
if (!rootDir.isDirectory()){
System.out.println("输入路径非法");
return;
}
//2.递归进行遍历
scanDir(rootDir,word);
}
private static void scanDir(File rootDir, String word) throws IOException {
//1.先列出rootDir中都有哪些内容
File[] files=rootDir.listFiles();
if (files==null){
return;
}
// 2. 遍历每个元素, 针对普通文件和目录分别进行处理.
for (File f:files){
if (f.isFile()){
//普通文件的话针对内容进行查找
if (containsWord(f,word)){
System.out.println(f.getCanonicalPath());
}
}else if (f.isDirectory()){
//目录文件的话进行递归遍历
scanDir(f,word);
}
}
}
private static boolean containsWord(File f, String word) {
StringBuilder stringBuilder=new StringBuilder();
// 把 f 中的内容都读出来, 放到一个 StringBuilder 中
try(Reader reader=new FileReader(f)) {
char[] buffer=new char[1024];
while (true){
int len=reader.read(buffer);
if (len==-1){
break;
}
// 把这一段读到的结果, 放到 StringBuilder 中
stringBuilder.append(buffer,0,len);
}
}catch (IOException e){
e.printStackTrace();
}
// indexOf 返回的是子串的下标. 如果 word 在 stringBuilder 中不存在, 则返回下标为 -1
return stringBuilder.indexOf(word)!=-1;
}
}
运行:
执行代码后,成功在当前项目目录下找出了包含关键词aaa的所有文件(绝对路径);
- 写到这里,关于Java中的文件操作–IO 相关讲解就已经完成了 !
- 完结撒花 over ~ 🎈