文件操作 与 IO

🍉作者@ Autumn60
🏄欢迎关注:👍点赞🙌收藏✍️留言
👲微语: 这个世界永远比你想的要精彩,没有所谓的运气,只有绝对的努力,生活每天都有限量版,请带着你的坚持一起挑战!


目录

一、文件操作

1.文件系统

        1.1文件的结构:

        1.2路径:

二、文件内容操作,流对象

2.1 File 类

属性:

构造方法:

方法: 

2.2 流

1.读文件:

 InputStream 类:

2.写文件

OutputStream  类

3.关闭操作(释放资源)


一、文件操作

       平时谈到的“文件”,指的是硬盘上的文件

 这章主要讲 创建文件,删除文件,重命名文件,创建目录        

学习之前首先要知道什么是路径 和 文件的结构

1.文件系统

        1.1文件的结构:

                计算机上的目录是有层级结构

在计算机里,保管储存文件是通过操作系统中的“文件系统”来实现的。

而文件系统中一般是通过树形结构来组织磁盘上的目录和文件的,文件是以树形结构来进行存储的,一颗N叉数

图例:                这就是树形结构

        1.2路径:

 红框,框出来的就是路径,也就是文件系统上一个文件 / 目录 的具体位置  (目录也是文件夹);

文件路径:

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

Windows 都是从"此电脑" 起头的,所以在表示路径的时候,可以吧 "此电脑"省略,直接从 盘符 开始表示,所以一般看到的也就是从C盘 、D盘、F盘起头的这种,也就是上图中的样子。

实际表示路径,是通过一个字符串表示,每个目录之间使用  /  或者 \  来分割 建议使用  /  ,用反斜杠的话需要使用转义字符;

         1.相对路径:

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

  •         相对路径一定要明确,基准目录(工作目录)是啥
  •         相对路径会随着你工作目录的变化而变化
  •         .     在相对路径中,是一个特殊符号,表示当前目录
  •         ..    也是特殊符号,表示当前目录的上级目录

图例:               

相对路径的表示:假设此时工作目录是Code,则相对路径是./177/out /production

        2.绝对路径

                从盘符开始,一层一层的往下找,得到的路径,就是绝对路径

图例:


小结: 

  1. 文件系统上,任何一个文件,对应的路径,也是唯一的,在Windows上(路径和文件是一一对应的)
  2. 也就是不会存在,两个路径相同,但是文件不同的情况!
  3. 在Linux 上,可能存在一个文件,有两个不同的路径找到它  (了解即可,本章不展开说)  
  4. 但是在Windows上,不可能存在

二、文件内容操作,流对象

通过一组类来操作;

如何进行文件系统操作呢?在Java标准库中提供了一个类,File 类!

  • File 对象是硬盘上的一个文件的抽象表示;
  •        文件是存储在硬盘上面的,直接通过代码操作硬盘,不太方便,就在内存中创建一个对应的对象,这时候操作这个内存中的对象,就可以间接的影响到硬盘的文件了(和电视剧的遥控板一样)

2.1 File 类

属性:

构造方法:

方法: 

代码示例: 

import java.io.File;
import java.io.IOException;
public class Main {
    public static void main(String[] args) throws IOException {
        File file = new File("..\\hello-world.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());
   }
}

执行结果:


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

针对二进制文件,提供了一组类,统称为 “ 字节流 ” ,(典型代表,InputStream,OutputStream)


2.2 流

流(Stream) /类别 :

什么是流?

而每种流又分为两种:

输入:   reader , InputStream;

输出:   Writer,  OutputStream


1.读文件:

 InputStream 类:

        代码:

public class Main {
    public static void main(String[] args) throws IOException {
        InputStream inputStream = new FileInputStream("d/.cat.jpg");
    }
}
  •         如果在代码执行完不执行close 操作,就可能会导致 文件描述符表溢出问题;
  •         在读文件时,如果出现一些问题,比如说 return 或者 抛出异常 ,就会导致 close 执行不到了,这时候可以通过try 和 finally 来保证执行close 操作

        加入  try  和 finally 来保证 close 一定能被执行到;

public class Main {
    public static void main(String[] args) throws IOException {
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream("d/.cat.jpg");
        } finally {
            //通过加入finally 来保证资源释放一定能被执行到
            inputStream.close();
        }
    }
}

       但是上述这种写法,太繁琐,而且不好看(优雅);

try(InputStream inputStream = new FileInputStream("d:/cat.txt")){
    
}

这种写法也 叫作 : try with resources 操作 ,其实就是带有资源的 try 操作, 会在 try 代码块结束,自动执行   close 关闭操作;

  1. 为什么会自动执行close 呢? 因为 InputStream 实现了一个特定的 interface 接口 Closeable;
  2. 也就是你实现了Closeable 这样的接口,就可以写成这样的语法

代码:

public class Main {
    public static void main(String[] args) throws IOException {
        try (InputStream inputStream = new FileInputStream("d:/cat.text")) {
            //read 一次读的是一个字节,如果一个文件读取完了,到头了,再次read 就会返回 -1;
            while(true) {
                int b = inputStream.read();
                if(b == -1) {
                    break;//代码走到这,也就是说明文件读到末尾了,结束循环即可;
                }
                System.out.println(b);
            }
        }
    }
}

运行结果:

图中可以看出,每次读的是字节,因为每次读取一个字节,读出的这一串数据,就是每个字符的ASCII码!

2.写文件

OutputStream  类

        方法:

 代码:

a.一次写一个字节:

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Demo1 {
    public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("d:/dog.txt")) {
            //通过OutputStream 来进行写操作;
            outputStream.write(97);
            outputStream.write(98);
            outputStream.write(99);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

执行完毕查看文件

b.一次写多个字节:

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Demo1 {
    public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("d:/dog.txt")) {
            //通过OutputStream 来进行写操作;
            //一次性写了4个
            byte[]tmp = new byte[]{97,98,98,97};
            outputStream.write(tmp);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

结果: 

3.关闭操作(释放资源)

        close 即可

三个代码案例:

1.遍历目录,在里面的文件内容中查找(全文检索)

        目标:

  • 电脑上面有很多目录,目录里面又有很多的文件~而每个文件里面又有很多的内容
  • 假设某些文件中,包含"hello world " 关键词;
  • 这个程序就是找出哪些文件,是包含这个关键词的~

实现方式:

  1. 递归遍历目录 , 比如给定一个 d:/  去递归 把这里包含的所有文件都列出来;
  2. 每次找到一个文件,都打开,并读取文件内容(得到 String);
  3. .在判定要查询的词,是否在上述文件内容中存在,如果存在,结果即为所求;

只适用于小规模的搜索;

如果要想用大规模,可以使用倒排索引;

代码:

import java.io.*;
import java.util.Scanner;

public class Demo3 {
    public static void main(String[] args) {
        //1.让用户输入一个想要搜索的根目录
        //2.把输入的目录放进去,判断目录的输入的合法性;
        //3.让用户输入一个想要查询的词;
        //4.递归的进行目录/文件的遍历了;
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个你想要遍历的目录 : ");
        File file = new File(sc.next());
        //判断用户输入的目录是否是合法的!
        if(!file.isDirectory()) {
            System.out.println("输入目录有误");
            return;
        }
        //2.让用户输入一个要查询的词;
        System.out.println("请输入要查询的词");
        String word = sc.next();
        //3.递归的进行目录的遍历
        scanDir(file,word);
    }

    private static void scanDir(File file, String word) {
        //列出file中的内容,也就是查看输入的目录下面有没有文件,如果没有就直接结束;
        //列出file中的内容,用数组接受
        File[] files = file.listFiles();
        if (files == null) {
            //如果等于空,那就是啥也没有;
            return;
        }
        for (File f : files) {
            System.out.print(f.getAbsolutePath());
            if(f.isFile()) {
                     //判断此刻拿到的是否是普通文件
                    //如果是普通文件,就打开,然后读取文件,判断是否包含;如果包含,就打印,不包含继续;
                    String cont = read(f);
                    if(cont.contains(word)) {
                        //如果包含就打印路径
                        System.out.println(f.getAbsolutePath() + "包含");
                    }
            } else if(f.isDirectory()) {
                    //判断拿到的是否是目录文件
                    //目录文件就继续进行递归即可;
                    scanDir(file,word);
            } else {
                    //如果上面两种都不是跳过即可;
               continue;
            }
        }
    }

    private static String read(File f) {
        StringBuilder stringBuilder = new StringBuilder();
        try(Reader reader = new FileReader(f)) {
            while(true) {
                //把读出来的每一个字符全部放到stringBuilder;
                int c  = reader.read();
                //读到-1就代表已经读取结束了;
                if (c == -1) {
                    break;
                }
                stringBuilder.append((char)c);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //返回即可
        return stringBuilder.toString();
    }
}

执行结果:

  1. 类似于一个 先序遍历
  2. 先访问根目录,把根目录里的内容都列出来
  3. 再一次遍历子目录
  4. 如果根目录没有子目录,就直接遍历完了

如果查询根目录太大的话就会报错;     读着读着超过内存容量就会报错;

本章节重点:

        字节流:InputStream  OutputStream

        字符流  Reader Write

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Autumn60

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值