文件IO操作
1.文件简介
狭义的文件:保存在硬盘上的文件
广义的文件:操作系统惊醒资源管理的一种机制,很多的软件/硬件资源,抽象成“文件”来进行表示
| 组件 | 角色定位 | 速度(快→慢) | 容量(小→大) | 价格(每GB) | 数据持久性 |
|---|
| CPU | 大脑、指挥官 | 极快 | 极小(缓存:MB级别) | 极贵 | 断电后数据消失 |
| 内存 | 临时工作台 | 很快 | 较小(GB级别:8GB, 16GB, 32GB) | 中等 | 断电后数据消失 |
| 硬盘 | 长期仓库 | 较慢 | 极大(TB级别:512GB, 1TB, 2TB) | 便宜 | 断电后数据保留 |
计算机中文件的存储是树形结构(N叉树),我们通过路径来查找文件,一般使用/来分割路径中的多级目录。
例如: ./text.txt 。 ./表示当前目录 ../text.txt ../表示上一级目录
2.文件的种类
1.文本文件:文本文件是一种以字符序列形式存储数据的文件。每个字符都根据一个标准编码规则(现在最常用的是 UTF-8)映射为一个或多个字节的数字。
2.二进制文件:二进制文件不关心人类可读性,它直接以数据的原始二进制格式存储信息。程序按照预先定义好的、严格的格式来解读这些二进制位的含义。
为了区分一个文件到底是二进制文件还是文本文件,可以将一个文件用记事本打开。
3.在java中操作文件
1.文件系统操作
文件系统操作包括创建文件,删除文件,重命名,创建,删除目录
File类用来对文件进行操作。
在操作系统看来,重命名和移动操作本质上是一样的。
// 示例一
public static void main(String[] args) throws IOException {//创建代表文件路径的对象。File file = new File("./text.txt");System.out.println(file.getParent()); //得到该文件所在目录System.out.println(file.getName()); //文件名称System.out.println(file.getPath()); //文件路径System.out.println(file.getAbsolutePath()); //文件的绝对路径,不解析 .System.out.println(file.getCanonicalPath()); //规范路径 解析.}//示例二public static void main(String[] args) throws IOException {File file = new File("./text.txt");file.createNewFile(); //创建文件System.out.println(file.exists());System.out.println(file.isFile());System.out.println(file.isDirectory());}//示例三
public static void main(String[] args) throws InterruptedException {File file = new File("./text.txt");boolean res = file.delete();System.out.println(res);file.deleteOnExit(); //在进程退出时删除文件Thread.sleep(10000); //在10秒后删除}//示例四
public static void main(String[] args) {//针对文件无法进行list操作//必须针对目录才可以System.out.println("==============================");File file = new File("c:/");String []list = file.list();System.out.println(Arrays.toString(list));System.out.println("==================================");File[] files = file.listFiles();System.out.println(Arrays.toString(files));}//示例五
public static void main(String[] args) {File file = new File("./test2/111/222/333");//mkdir无法创建多级目录,只能创建一级boolean res = file.mkdirs();file.delete();System.out.println(res);}//示例六public static void main(String[] args) {// 重命名还能起到 "移动" 的作用File file = new File("./test2");File newFile = new File("./src/test2");boolean result = file.renameTo(newFile);System.out.println(result);}
2.文件内容操作
对文件内容进行读和写,主要是通过一组“流对象”来实现的。
对文件内容进行读写时,打开文件之后需要关闭,否则会造成错误。但是在java1.5之后,引入了try with resources语法
2.1字节流
读写文件以字节为单位,是针对二进制文件使用的
inputStream 输入 从文件读数据
outputStream 输出 往文件写数据
//示例一
public static void main(String[] args) throws IOException {try(InputStream inputStream = new FileInputStream("./text.txt")){//读文件操作while(true){//一次读一个字节
// int data = inputStream.read();
// if(data == -1){
// break;
// }
// System.out.printf("0x%x\n", data);//一次读多个字节,数组的长度,自行定义byte[] data = new byte[3];int n = inputStream.read(data);if(n == -1){//文件读完break;}for(int i =0 ;i < n;i++){System.out.printf("0x%x\n",data[i]);}System.out.println("===============");}}}//示例二
//可追加,true时为可追加写try(OutputStream outputStream = new FileOutputStream("./output.txt",true)){outputStream.write(97); //字母aoutputStream.write(98); //字母bbyte[] bytes = {99}; //字母coutputStream.write(bytes);}catch (IOException e){throw new RuntimeException();}
2.2.字符流
读写文件以字符为单位,是针对文本文件使用的
Reader 输入 从文件读数据
Writer 输出 往文件写数据
//示例一
public static void main(String[] args) throws IOException {try(Reader reader = new FileReader("./text.txt")){while(true){char[] buf = new char[1024];int n = reader.read(buf);if(n == -1){break;}for(int i = 0;i < n;i++){System.out.print(buf[i]);}}}}//示例二
public static void main(String[] args) throws IOException {
// try (Writer writer = new FileWriter("./output2.txt", true)) {
// BufferedWriter bufferedWriter = new BufferedWriter(writer);
// bufferedWriter.write("Hello World");
// } catch (IOException e) {
// throw new RuntimeException(e);
// }// 更简洁的写法 优化try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("./output2.txt", true))) {bufferedWriter.write("Hello World");bufferedWriter.newLine(); // 添加换行} catch (IOException e) {throw new RuntimeException(e);}}
2.3流对象的使用流程
1.先打开,再读写,最后关闭
2.区分应该使用哪个流对象? 先区分文件是文本还是二进制,再区分读还是写
对文件进行读和写时(read和write)时,要想提高效率,方法如下:
1.写代码的时候,手动创建(byte[]),手动减少read write次数
2.使用代码标准库提供的“缓冲区流”,BufferedStream ,把inputStream之类的对象套上一层
3.例题
示例1
扫描指定⽬录,并找到名称中包含指定字符的所有普通⽂件(不包含⽬录),并且后续询问⽤⼾是否 要删除该⽂件
public class Demo11 {public static void main(String[] args) throws IOException {Scanner scanner = new Scanner(System.in);System.out.println("请输入要搜索的目录:");String rootDir = scanner.next();File rootFile = new File(rootDir);if(!rootFile.isDirectory()){System.out.println("输入的不是目录!");return;}System.out.println("请输入要删除的关键字");String keyword = scanner.next();scanDir(rootFile,keyword);}private static void scanDir(File rootFile,String keyword){//1.列出当前目录包含的内容File[] files = rootFile.listFiles();if(files == null){//如果当前是空目录return;}for (File file : files) {System.out.println("遍历的目录文件" + file.getAbsolutePath());if (file.isFile()) {dealFile(file, keyword);} else {//5.如果是目录,则递归调用本方法scanDir(file, keyword);}}}private static void dealFile(File file,String keyword){if(file.getName().contains(keyword)){System.out.println("发现文件:" + file.getAbsolutePath() + ",包含关键字");System.out.println("是否要删除,y = 删");Scanner scanner = new Scanner(System.in);String input = scanner.next();if(input.equalsIgnoreCase("y")){file.delete();System.out.println("文件已删除");}}}
示例2
进⾏普通⽂件的复制
public class Demo12 {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入源文件路径:");String srcPath = scanner.next();System.out.println("请输入目标文件路径:");String destPath = scanner.next();File srcFile = new File(srcPath);if(!srcFile.isFile()){System.out.println("源文件不存在或不是文件" );return ;}File destFile = new File(destPath);//要求destFile不一定存在//但是destFile所在的目录必须存在if(!destFile.getParentFile().isDirectory()){System.out.println("目标文件所在目录不存在");return;}// 真正进行复制文件的操作// 此处不应该使用追加写. 需要确保目标文件和源文件一模一样.try(InputStream inputStream = new FileInputStream(srcFile);OutputStream outputStream = new FileOutputStream(destFile)) {while(true){byte[] buf = new byte[1024];int n = inputStream.read(buf);if(n==-1){break;}outputStream.write(buf,0,n);}} catch (IOException e) {throw new RuntimeException(e);}}
示例3
扫描指定⽬录,并找到名称或者内容中包含指定字符的所有普通⽂件(不包含⽬录)
public class Demo13 {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 keyword = scanner.next();scanDir(rootFile,keyword);}private static void scanDir(File rootFile,String keyword){//列出当前目录下的所有内容File[] files = rootFile.listFiles();if(files == null){return ;}for(File file: files){if(file.isFile()){dealFile(file,keyword);}else{//是目录,递归调用scanDir(file,keyword);}}}private static void dealFile(File file,String keyword) {//判断文件是否包含if(file.getName().contains(keyword)){System.out.println("文件名包含关键字" + file.getAbsolutePath());return ;}//2.判断文件内容是否包含关键字StringBuilder stringBuilder = new StringBuilder();try(Reader reader = new FileReader(file)){while(true){char [] chars = new char[1024];int n = reader.read(chars);if(n == -1){break;}stringBuilder.append(chars,0,n);}}catch (IOException e){throw new RuntimeException(e);}//3.判定stringBuilder是否包含关键字if(stringBuilder.indexOf(keyword) >= 0){System.out.println("文件内容包含关键字" + file.getAbsolutePath());}return ;}
}
