当前位置:   article > 正文

文件认识及操作(读写文件)_什么是数据文件读写

什么是数据文件读写

目录

一.文件

1.什么是文件

2.目录结构(基本常识)

二.File类的用法

1.File类

2.读文件和写文件

3.练习1--扫描指定目录

4.练习2--普通文件的复制

一.文件

1.什么是文件

  • 狭义上的文件:存储在硬盘上的数据,以“文件”为单位进行组织,常见的文件比如文本文件、图片、音频、可执行程序等。文件夹(目录)也是一种特殊的文件。硬盘的特点(相较于内存):存储空间大;访问速度慢;成本较低;断电数据不会丢失,持续化存储。
  • 广义上的文件:操作系统负责管理软硬件资源,操作系统会将这些资源抽象成“文件”来管理。例如从键盘读取数据就是把键盘抽象成文件,读这个文件就能读键盘输入的内容。

2.目录结构(基本常识)

  • 我们可以看到我们电脑文件夹是一层一层递进,且上层文件夹里可能会包含多个文件夹,这样就构成了一个树形结构。
  • 那我们如何描述我们的文件目录呢,通过“路径”就可以描述文件在电脑中的位置。路径分为绝对路径和相对路径。
  • 描述一个文件所在位置叫做绝对路径:E:\IntelliJ IDEA 2021.2\bin\idea64.exe,每个\分割的部分都是目录。
  • 相对路径:以基准路径(工作路径)为起点,怎么继续往下走才能找到目标路径,也就是找“参考系”。比如你要去一个陌生的地方,但是需要问路,每到一个地方问一次,那么每次这条路的起点是你脚下的地方,而不是你最开始问路的地方。这就叫做基准路径不同。
  • 以上述绝对路径为例,当基准路径是E:此时的相对路径就是./IntelliJ IDEA 2021.2/bin/idea64.exe,如果基准路径是E:/IntelliJ IDEA 2021.2,此时的相对路径就是./bin/idea54.exe……以此类推,就是相对路径的描述方式。如果基准路径是其他文件夹,那么就需要使用 .. 返回上级目录,直到返回要找的文件所在的目录。找工作目录比较复杂,不同的情况下工作目录所在的位置不一定是固定的。

二.File类的用法

1.File类

  • File类:这个类在java.io包中,IO就是输入输出。
  • File类中有很多方法供我们使用,包括返回 File 对象的父目录文件路径、返回 FIle 对象的纯文件名称 返回 File 对象的文件路径 返回 File 对象的绝对路径 等。其中File(String pathname)构造方法就能让我们创建对象时指定一个路径。
  • 构建File对象:
  1. import java.io.IOException;
  2. //观察 get 系列的特点和差异
  3. public class Demo1 {
  4. public static void main(String[] args) throws IOException {
  5. // File f = new File("D:/test.txt");//绝对路径
  6. File f = new File("./test.txt");//相对路径
  7. System.out.println(f.getParent());
  8. System.out.println(f.getName());
  9. System.out.println(f.getPath());
  10. System.out.println(f.getAbsolutePath());
  11. System.out.println(f.getCanonicalPath());
  12. //绝对路径运行结果
  13. //D:\
  14. //test.txt
  15. //D:\test.txt
  16. //D:\test.txt
  17. //D:\test.txt
  18. //后面三种结果看起来一样,其实不同,如果变换构造File的路径,运行结果不同
  19. //相对路径运行结果
  20. //.
  21. //test.txt
  22. //.\test.txt
  23. //E:\2022code\Java-language\system_code\.\test.txt
  24. //E:\2022code\Java-language\system_code\test.txt
  25. }
  26. }
  • 上述结果虽然运行出来了,但我们不知道是否有这个文件,可以判断文件是否存在:
  1. import java.io.File;
  2. import java.io.IOException;
  3. public class Demo2 {
  4. public static void main(String[] args) throws IOException {
  5. File f = new File("./test.txt");
  6. //判断文件是否存在,存在就返回true,不存在就返回false
  7. System.out.println(f.exists()); //false
  8. //判断类型,是否是个目录
  9. System.out.println(f.isDirectory()); //false
  10. //判断是否是个普通文件
  11. System.out.println(f.isFile()); //false
  12. //创建这个不存在的文件,创建文件会抛出异常
  13. f.createNewFile();
  14. //判断文件是否存在,存在就返回true,不存在就返回false
  15. System.out.println(f.exists()); //true
  16. //判断类型,是否是个目录
  17. System.out.println(f.isDirectory()); //false
  18. //判断是否是个普通文件
  19. System.out.println(f.isFile()); //true
  20. }
  21. }
  • 删除文件:
  1. //删除文件
  2. //创建文件成功后在项目目录下会生成一个test.txt文件,删除文件运行后,相应的文件被删除掉。
  3. import java.io.File;
  4. public class Demo3 {
  5. public static void main(String[] args) {
  6. File f = new File("./test.txt");
  7. f.delete();
  8. }
  9. }
  • 除此之外还有createNewFile()创建空文件、delete()删除文件、deleteOnExit() 进程退出时删除文件、 mkdir()创建目录、mkdirs()创建多级目录、renameTo重命名等。
  • 创建目录:
  1. //创建目录
  2. //和删除文件一样,程序不会有任何的提示,创建目录项目会在system_code目录下生成一个目录
  3. import java.io.File;
  4. public class Demo4 {
  5. public static void main(String[] args) {
  6. // File f = new File("./testDir");
  7. File f = new File("./testDir/aaa/bbb");//创建多级目录
  8. //make directory 创建目录
  9. f.mkdir();//创建单层目录
  10. f.mkdirs();//创建多层目录
  11. }
  12. }
  • 重命名:
  1. //重命名
  2. import java.io.File;
  3. public class Demo5 {
  4. public static void main(String[] args) {
  5. File sreFile = new File("aaa.txt");
  6. File destFile = new File("bbb.txt");
  7. sreFile.renameTo(destFile);//把文件名从aaa改成bbb
  8. }
  9. }
  • list():
  1. //list() 返回 File 对象代表的目录下的所有文件名
  2. import java.io.File;
  3. import java.util.Arrays;
  4. public class Demo6 {
  5. public static void main(String[] args) {
  6. File f = new File("./testDir");
  7. String[] results = f.list();
  8. System.out.println(Arrays.toString(results));
  9. //[aaa, bbb, ccc, ddd]
  10. }
  11. }
  • 以上操作都只是在操作文件系统,并没有对文件内容进行操作。

2.读文件和写文件

  • 流(stream):我们把读写文件操作比喻成水流,将数据视为池中的水,写叫做输出流,读就是输入流(以CPU/内存为参照)。
  • 在Java中提供了一组类完成读写文件操作,按照不同的特点进行划分,可以分为字节流(以字节为基本单位)和字符流(以字符为基本单位),字节流适用于二进制文件、字符流适用于文本文件;字节流分为InputStream和OutputStream,字符流又分为Reader和Writer;上述四个类都属于父类,Java中还给这些父类提供了相应的子类来实现不同场景下的读写操作。
  • InputStream提供的方法:read()一次读一个字节,读出的结果作为read的结果;read(byte[] b)及read(byte[] b,int off, int len)都是把读到的内容放到参数字节数组b中,参数b用来存放方法读取的结果,此时b成为“输出型参数”。
  • 例如读文件:
  1. //读文件
  2. import java.io.FileInputStream;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. public class Demo7 {
  6. public static void main(String[] args) throws IOException {
  7. //InputStream 是一个抽象类,不具体,不能实例化
  8. //相当于打开文件操作,要想读文件就必须先打开文件
  9. InputStream inputStream = new FileInputStream("./bbb.txt");
  10. while (true) {
  11. int b = inputStream.read();
  12. // 读到文件末尾
  13. if (b == -1) {
  14. break;
  15. }
  16. System.out.println(b);
  17. }
  18. //读完必须关闭文件
  19. inputStream.close();
  20. }
  21. }
  22. // 此处使用字节流读取文件的结果是字符的ASCAII值
  1. //字符流读文件
  2. public class Demo2 {
  3. public static void main(String[] args) throws IOException {
  4. //使用字符流读文件
  5. Reader reader = new FileReader("./bbb.txt");
  6. while (true) {
  7. int ret = reader.read();
  8. if(ret == -1) {
  9. break;
  10. }
  11. char ch = (char)ret;
  12. System.out.println(ch);
  13. }
  14. //用完之后要关掉
  15. reader.close();
  16. }
  17. }
  18. // 使用字符流读文件获取到的就是文件本身的字符
  1. // 针对文本文件,使用字符流的时候还可以使用Scanner读取文件(简化方法)
  2. public class Demo4 {
  3. public static void main(String[] args) throws IOException {
  4. //使用Scanner 读文本文件
  5. InputStream inputStream = new FileInputStream("./bbb.txt");
  6. Scanner scanner = new Scanner(inputStream);
  7. while (scanner.hasNext()) {
  8. System.out.println(scanner.next());
  9. }
  10. inputStream.close();
  11. }
  12. }

  • 写文件:

  1. //字节流写文件
  2. public class Demo1 {
  3. //进行写文件
  4. public static void main(String[] args) throws IOException {
  5. OutputStream outputStream = new FileOutputStream("./bbb.txt");
  6. //使用outputstream写文件的时候,只要打开文件成功,就会把原有的文件内容清空。bbb文件内容变为abc
  7. //小写字母的ascii码值对应的数字
  8. outputStream.write(97);
  9. outputStream.write(98);
  10. outputStream.write(99);
  11. outputStream.close();
  12. }
  13. }
  1. public class Demo3 {
  2. public static void main(String[] args) throws IOException {
  3. //使用字符流来写文件
  4. Writer writer = new FileWriter("./bbb.txt");
  5. writer.write("Hello world");
  6. writer.close();
  7. }
  8. }
  1. // 针对写文本文件,还可以使用 PrintWriter(简化方法)
  2. public class Demo5 {
  3. public static void main(String[] args) throws IOException {
  4. // try with resources 把要关闭的对象写到try()里,当try结束,就会自动的调用到对应对象的close方法。
  5. // 而且支持一个 () 放多个对象,多个对象的创建之间使用;分割。
  6. try (OutputStream outputStream = new FileOutputStream("./bbb.txt")){
  7. PrintWriter writer = new PrintWriter(outputStream);
  8. writer.println();
  9. writer.print("a = %d\n, 10");
  10. }
  11. }
  12. }

❗❗进行文件操作一定要关闭文件,原因是每个进程都对应着PCB,PCB里有一个字段是文件描述表,同一个进程里多个PCB共用一份文件描述符表,文件描述表就相当于一个数组(最大长度有上限),进程每打开一个文件就会在这个表里创建一个项(数组里的元素),关闭文件就会将这个项释放掉,如果不关闭文件,这个表项就会一直占着位置,持续打开文件且不关闭,就会耗尽表项,后续再打开文件就会打开失败(文件资源泄露,严重性大于程序崩溃)。JVM其实有自动释放策略的,但是需要被GC销毁,自动关闭对应的文件,但是这也是需要你给JVM通知一下的,可能存在隐患。服务器长期持续执行,更担心这种问题的存在。

3.练习1--扫描指定目录

  1. //扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包含目录),并且后续询问用户是否要删除该文件
  2. public class Demo6 {
  3. public static void main(String[] args) throws IOException {
  4. // 1.让用户输入必要的信息(要扫描的路径+要查找的词)
  5. Scanner scanner = new Scanner(System.in);
  6. System.out.println("请输入要扫描的路径:");
  7. //判定路径是否存在
  8. File rootDir = new File(scanner.next());
  9. if (!rootDir.isDirectory()) {
  10. System.out.println("您输入的目录不存在!");
  11. return;
  12. }
  13. System.out.println("请输入要搜索的关键词:");
  14. String toDelete = scanner.next();
  15. // 2.遍历目录,找到名字配匹配的文件。
  16. // 需要借助一个核心方法,listFiles()
  17. // 能够把当前目录里的文件和子目录列举出来,但是这个方法只能列出一层,没法直接列出子目录中的子目录。
  18. // 解决方法就是遍历listFiles 的结果,针对每个元素,进行判定,看它是一个普通文件还是一个目录,
  19. // 如果是普通文件,直接判定文件名是否包含了要查的词,如果是目录,递归调用listFiles。
  20. scaDir(rootDir,toDelete);
  21. }
  22. //借助这个方法进行递归遍历,相当于递归遍历n叉树
  23. private static void scaDir(File rootDir,String toDelete) throws IOException {
  24. System.out.println("当前访问: " + rootDir.getCanonicalPath());
  25. File[] files = rootDir.listFiles();
  26. if (files == null) {
  27. //说明 rootDir 是一个空的目录
  28. return;
  29. }
  30. //如果目录非空,则循环遍历里面的每个元素
  31. for (File f : files) {
  32. if (f.isDirectory()) {
  33. scaDir(f,toDelete);
  34. } else {
  35. //不是根目录,普通文件,判定文件名是否符合要求,是否要进行删除
  36. checkDelete(f,toDelete);
  37. }
  38. }
  39. }
  40. // 3.询问用户是否删除
  41. private static void checkDelete(File f, String toDelete) throws IOException {
  42. if (f.getName().contains(toDelete)) {
  43. System.out.println("该单词" + toDelete + "被" + f.getCanonicalPath() + "包含了,是否要删除?(Y/N)");
  44. Scanner scanner = new Scanner(System.in);
  45. String choice = scanner.next();
  46. if (choice.equals("Y") || choice.equals("y")) {
  47. f.delete();
  48. }
  49. }
  50. }
  51. }

升级版(性能较低,查找过程会很漫长):

  1. //在扫描指定目录的基础上增加了查找内容的功能
  2. public class Demo8 {
  3. public static void main(String[] args) throws IOException {
  4. // 1. 输入路径和要查询的关键词
  5. Scanner scanner = new Scanner(System.in);
  6. System.out.println("请输入要扫描的路径: ");
  7. File rootDir = new File(scanner.next());
  8. System.out.println("请输入要查询的词: ");
  9. String toFind = scanner.next();
  10. // 2. 递归的扫描目录.
  11. scanDir(rootDir, toFind);
  12. }
  13. // 递归操作
  14. private static void scanDir(File rootDir, String toFind) throws IOException {
  15. File[] files = rootDir.listFiles();
  16. // 空目录
  17. if (files == null) {
  18. return;
  19. }
  20. for (File f : files) {
  21. if (f.isDirectory()) {
  22. scanDir(f, toFind);
  23. } else {
  24. checkFile(f, toFind);
  25. }
  26. }
  27. }
  28. private static void checkFile(File f, String toFind) throws IOException {
  29. // 1. 先检查文件名
  30. if (f.getName().contains(toFind)) {
  31. System.out.println(f.getCanonicalPath() + " 文件名中包含 " + toFind);
  32. }
  33. // 2. 再检查文件内容
  34. try (InputStream inputStream = new FileInputStream(f)) {
  35. StringBuilder stringBuilder = new StringBuilder();
  36. Scanner scanner = new Scanner(inputStream);
  37. // 按行读取
  38. while (scanner.hasNextLine()) {
  39. // 把换行拼接到文件中
  40. stringBuilder.append(scanner.nextLine() + "\n");
  41. }
  42. // 判断文件中是否包含要查找的词
  43. if (stringBuilder.indexOf(toFind) > -1) {
  44. System.out.println(f.getCanonicalPath() + " 文件内容包含 " + toFind);
  45. }
  46. }
  47. }
  48. }

4.练习2--普通文件的复制

  1. // 进行普通文件的复制
  2. // 把第一个文件打开,把里面的内容逐个字节的读取出来,写到第二个文件即可
  3. // 使用字节流来进行操作,字节流也是可以用来拷贝文本文件的
  4. public class Demo7 {
  5. public static void main(String[] args) {
  6. // 1. 先输入需要复制的文件(源文件), 以及需要把这个文件复制到哪里去(目标文件)
  7. Scanner scanner = new Scanner(System.in);
  8. System.out.println("请输入源文件: ");
  9. // srcFile : d:/cat.jpg
  10. File srcFile = new File(scanner.next());
  11. System.out.println("请输入目标文件: ");
  12. // destFile : d:/cat2.jpg
  13. File destFile = new File(scanner.next());
  14. // 判断源文件是否存在
  15. if (!srcFile.isFile()) {
  16. System.out.println("输入源文件错误!");
  17. return;
  18. }
  19. // 判断目标文件是否存在
  20. if (!destFile.getParentFile().isDirectory()) {
  21. System.out.println("输入目标文件错误!");
  22. return;
  23. }
  24. // 2. 打开源文件, 按照字节读取内容, 依次写入到目标文件中.
  25. // 同时打开多个文件
  26. try (InputStream inputStream = new FileInputStream(srcFile);
  27. OutputStream outputStream = new FileOutputStream(destFile)) {
  28. // 读 src 的每个字节, 写入到 dest 中.
  29. while (true) {
  30. int ret = inputStream.read();
  31. if (ret == -1) {
  32. break;
  33. }
  34. // 一边读一边写
  35. outputStream.write(ret);
  36. }
  37. } catch (IOException e) {
  38. e.printStackTrace();
  39. }
  40. }
  41. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/秋刀鱼在做梦/article/detail/852527
推荐阅读
相关标签
  

闽ICP备14008679号