欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 时评 > 【JavaEE初阶】文件IO(下)

【JavaEE初阶】文件IO(下)

2025/2/23 19:25:49 来源:https://blog.csdn.net/2301_80898480/article/details/142436774  浏览:    关键词:【JavaEE初阶】文件IO(下)

欢迎关注个人主页:逸狼


创造不易,可以点点赞吗~

如有错误,欢迎指出~



目录

 文件内容操作

打开 关闭文件

文件描述符表

字节流

读文件

写文件

字符流

读文件

写文件

Scanner 

示例一:通过scanner读取文件中的数字

示例二:扫描指定⽬录

示例三:实现文件复制


 文件内容操作

 文件内容操作:读文件 和 写文件,操作系统都提供了API,Java也进行了封装

Java实现IO流类 有很多,分为 字节流(二进制)和字符流(文本) 两大类

上面这四个类都是抽象类,Java中还提供了许多类 来实现这四个抽象类

  • 但凡类的名字以Reader Writer结尾的,就是实现了Reader和Writer的字符流对象
  • 但凡类的名字以InputStream OutputStream结尾的,就是实现了InputStream和OutputStream的字节流对象

在这里谈到的输入输出,都是以cpu视角来说的:

  • 数据远离cpu =>输出
  • 数据靠近cpu =>输入

打开 关闭文件

示例1

这种写法,虽然能够确保严谨,但是比较麻烦

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;public class Demo9_IO {public static void main(String[] args)  {InputStream inputStream=null;try {inputStream = new FileInputStream("./test.txt");//隐含了打开文件} catch (FileNotFoundException e) {e.printStackTrace();}finally{try {inputStream.close();//关闭文件} catch (IOException e) {e.printStackTrace();}}}
}

如果不使用close关不上,会发生什么?

打开文件 其实是在该进程的 文件描述符表 中,创建了一个新的表项

文件描述符表

文件描述符表 描述了该进程都需要哪些文件,可以认为是一个数组,数组的每个元素就是一个struct file 对象(Linux内核),每个结构体就描述了对应操作的文件信息,数组下标 就称为"文件描述符"

示例2:这种写法更简单可靠

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;public class Demo10 {public static <inputStream> void main(String[] args) {try(InputStream inputStream=new FileInputStream("./test.txt")) {} catch (IOException e) {e.printStackTrace();}}
}

这里代码中,不用写close关闭,因为close之后,紧接着就是进程的结束(意味着pcb就整个销毁,pcb上的文件描述符表,整个就释放了)

字节流

读文件

读文件 :数据从硬盘上读取到 内存里

示例1:读取test.txt文件的内容,以16进制方式输出

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;public class Demo10 {public static void main(String[] args) {try (InputStream inputStream = new FileInputStream("./test.txt")) {while (true) {int b = inputStream.read();if (b == -1) {// 读取完毕了break;}// 表示字节, 更习惯使用 十六进制 打印显示.System.out.printf("0x%x\n", b);}} catch (IOException e) {e.printStackTrace();}}
}

示例1代码 要频繁读取多次硬盘,当前硬盘的IO是消耗比较大

示例2:使用buffer(缓冲区,暂时存储某些数据),;将硬盘上的数据先填充到buffer内存的字节数组中,尽可能填满  ,虽然一次读的内容多了,但是仍然比一次读一个字节,分多次读效率要高不少

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;public class Demo11 {public static void main(String[] args) {try(InputStream inputStream = new FileInputStream("./test.txt")){while(true){byte[] buffer =new byte[1024];//n返回值表示read操作,实际读取到多少个字节int n=inputStream.read(buffer);if(n==-1){break;}for (int i = 0; i < n; i++) {System.out.printf("0x%x\n",buffer[i]);}}}catch(IOException e){e.printStackTrace();}}
}

写文件

写文件和读文件非常类似

一个一个字节写入

        try(OutputStream outputStream=new FileOutputStream("./test.txt")){outputStream.write(0x61);outputStream.write(0x62);outputStream.write(0x62);outputStream.write(0x62);}catch (IOException e){e.printStackTrace();}

这里的写操作,会默认把之前的内容清空(只要使用outputStream打开文件,内容就没了),再进行写操作,可以使用"追加写"操作,保持原内容不变,在末尾继续写入内容

InputStream/OutputStream读写数据就是按照字节来操作的,如果要读写字符(中文)的话,就需要程序员手动来区分出哪几个字节是一个字符,在确保把这几个字符作为整体来写入

字符流

为了方便处理字符,引入了字符流

读文件

使用字符流读取数据的过程,Java标准库内部就自动对数据的编码进行了转码

示例1:一个一个字符读入

        try(Reader reader= new FileReader("./test.txt")){while(true){int c=reader.read();if(c==-1){break;}char ch=(char)c;System.out.println(ch);}}catch(IOException e){e.printStackTrace();}

示例2:读取一串字符

try (Reader reader = new FileReader("./test.txt")) {char[] buffer = new char[1024];int n = reader.read(buffer);System.out.println(n);for (int i = 0; i < n; i++) {System.out.println(buffer[i]);}} catch (IOException e) {}

写文件

        try(Writer writer=new FileWriter("./test.txt",true)){writer.write("你好世界");}catch(IOException e){e.printStackTrace();}

Scanner 

读取文件还有一个好用的工具类:Scanner

示例一:通过scanner读取文件中的数字

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;public class Demo16_scanner {public static void main(String[] args) {try(InputStream inputStream=new FileInputStream("./test.txt")){Scanner scanner=new Scanner(inputStream);while(scanner.hasNextInt()){System.out.println(scanner.nextInt());}}catch(IOException e){e.printStackTrace();}}
}

示例二:扫描指定⽬录

并找到名称或者内容中包含指定字符的所有普通⽂件(不包含⽬录)

import java.io.File;
import java.util.Scanner;public class Demo17 {private static void scan(File currentFile, String key) {if (!currentFile.isDirectory()) {return;}File[] files = currentFile.listFiles();if (files == null || files.length == 0) {return;}for (File f : files) {if (f.isFile()) {// 针对普通文件进行处理.// 判定文件名是否符合要求并提示用户删除doDelete(f, key);} else {// 针对目录进行处理// 继续递归scan(f, key);}}}private static void doDelete(File f, String key) {if (!f.getName().contains(key)) {// 文件名中不包含指定的关键字.return;}// 提示用户, 是否确认要删除Scanner scanner = new Scanner(System.in);System.out.println(f.getAbsolutePath() + " 是否确认要删除 Y/n");String choice = scanner.next();if (choice.equals("Y") || choice.equals("y")) {f.delete();}}public static void main(String[] args) {System.out.println("请输入要搜索的路径: ");Scanner scanner = new Scanner(System.in);String rootPath = scanner.next();File rootFile = new File(rootPath);if (!rootFile.isDirectory()) {System.out.println("输入的路径不存在");return;}System.out.println("请输入要删除的文件名字的关键字");String key = scanner.next();// 进行递归查找scan(rootFile, key);}
}

示例三:实现文件复制

将一个文件里的每个字节都读出来,写入到另一个文件里

import java.io.*;
import java.util.Scanner;public class Demo18 {public static void main(String[] args) {//1.输入路径,并做校验Scanner scanner = new Scanner(System.in);System.out.println("请输入源文件的路径: ");String srcPath=scanner.next();File srcFile= new File(srcPath);if(!srcFile.isFile()){System.out.println("源文件路径有误");return;}System.out.println("请输入目标文件的路径: ");String destPath = scanner.next();File destFile =new File(destPath);if(!destFile.getParentFile().isDirectory()){System.out.println("目标文件路径有误");return;}//2.执行复制操作try(InputStream inputStream = new FileInputStream(srcFile);OutputStream outputStream = new FileOutputStream(destFile)){while(true){byte[] buffer =new byte[1024];int n=inputStream.read(buffer);System.out.println("n="+n);if(n == -1){break;}//需要把buffer写入到outputStream中outputStream.write(buffer,0,n);}}catch(IOException e){e.printStackTrace();}}
}

示例四

实现递归遍历目录"查找文件",按照文件的内容查询

import java.io.*;
import java.util.Scanner;public class Demo19 {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入要搜索的路径: ");String rootPath = scanner.next();File rootFile = new File(rootPath);if (!rootFile.isDirectory()) {System.out.println("要搜索的路径有误!");return;}System.out.println("请输入要搜索的查询词: ");String key = scanner.next();// 进行递归scan(rootFile, key);}private static void scan(File rootFile, String key) {if (!rootFile.isDirectory()) {return;}File[] files = rootFile.listFiles();if (files == null || files.length == 0) {return;}for (File f : files) {if (f.isFile()) {// 进行后续的查询操作doSearch(f, key);} else {// 进行递归scan(f, key);}}}private static void doSearch(File f, String key) {// 打开文件, 读取文件内容, 判定文件内容是否包含 keyStringBuilder stringBuilder = new StringBuilder();try (Reader reader = new FileReader(f)) {char[] buffer = new char[1024];while (true) {int n = reader.read(buffer);if (n == -1) {break;}String s = new String(buffer, 0, n);stringBuilder.append(s);}} catch (IOException e) {e.printStackTrace();}if (stringBuilder.indexOf(key) == -1) {// 未找到return;}// 找到了System.out.println("找到匹配的文件: " + f.getAbsolutePath());}
}

此处这里的代码逻辑 效率是非常低的,每次查询都会涉及大量的硬盘IO操作,尤其是硬盘上可能有一些大的文件

这种思路,不能适应频繁查询场景,也不能适应目录中文件数目特别多,特别大的场景(实现搜索引擎)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com