文件操作 | 基础+字节流

关于存储

首先我们需要先了解一下电脑的存储

  1. 硬盘 | 存储空间很大, 访问速度很慢, 速度比内存慢了3, 4个数量级。储存数据的时间很长, 断电后, 数据不会丢失
  2. 内存 | 存储空间比硬盘少了很多, 访问速度较快, 不能持续存储数据, 断电后数据就会丢失
  3. 缓存 | CPU的速度比内存的速度还要快上100+ 倍, 如果CPU的指令需要一直到内存中才能获取, 那么CPU的速度再快, 也要被缓慢的内存访问速度所拖累, 所以在计算上增加了缓存这个器件。
    实际上缓存就是一个临时储存区, 访问速度比内存快得多, 相反空间远小于内存, 断电后数据丢失, 可以存储CPU重复使用的数据或者可能会使用到的数据, 在缓存中找不到的数据再去内存中找, 这样就能进一步提升整体的运行速度。
  4. 寄存器 | 是CPU的组成部分, 同时访问速度也是最快的, 容量非常小, 断电后数据丢失, 用于储存计算机频繁使用的数据。

关于文件

 文件 | 即计算机中储存数据的容器

而计算机中是以树形结构来组织文件的, 文件夹(目录)就是非叶子结点, 普通文件就是叶子结点

在这里插入图片描述

以这个为例, 这个树形图大概是:

在这里插入图片描述

文件路径

知道了文件是通过树形结构组织的, 那么我们怎么找到目标文件呢 ? 或者说怎么去描述一个文件的位置呢 ? 这里就引出了文件路径, 文件路径包括绝对路径和相对路径。

绝对路径 |
从数据结构的角度上来说, 就是从根节点开始到目标文件的结点描述, 即为绝对路径。
例如下图, “宝藏” 的绝对路径是 D:/可删/222/宝藏

在这里插入图片描述

相对路径 |
从数据结构上说, 就是从某个结点开始, 到达目标文件的结点描述, 即为相对路径。
如上图 ↑, 在"可删"结点出发, 宝藏的相对路径为 ./222/宝藏
(以 ./ 或者 . ./ 开头的路径即相对路径)

这就好比你想知道 广州塔在哪, 手机地图说 中国广东省广州市海珠区阅江西路222号, 根节点即出发点是中国, 这个路径就是绝对路径。而如果你已经在广州市珠海区了, 你问路人广州塔在哪里, 他说阅江西路222号, 这里的出发路径是珠海区, 这个路径即是相对路径。

文件操作

在 Java 中有文件类, 即 File 类, File 类中比较常用的构造方法有 ↓

在这里插入图片描述

参数是绝对路径或者相对路径, 会根据路径创建一个 FIle 实例, 如果传入的字符串为空, 则抛出空指针异常。

关于 File 类的常用方法

返回值方法签名备注
StringgetName()返回File对象的名称
StringgetPath()返回File对象的路径
StringgetAbsolutePath()返回File对象的绝对路径
booleanexisits()判断File对象描述的文件是否真实存在
booleanisDirectory()判断是否是文件夹
booleanisFile()判断是不是普通文件(目录不算)
booleandelete()根据File对象来删除文件
String[]list()返回File对象目录下所有文件名字
File[]listFiles()返回File对象目录下所有文件

文件读写

这里涉及到了一个概念 流

流, 数据在设备之间传输称为流
IO流, 描述数据流动的方向, 以内存为准, 流入内存为输入流, 流出内存则为输出流

IO 流又分为字节流和字符流, 字符流(Reader 和 Writer)适合用来操作文本文件, 字节流适合用来操作二进制文件

InputStream | 输入流

InputStream 是一个抽象类, 无法实例化, 围绕今天的主题, 重点还是它的实现类 FileInputStream

FileInputStream 常用的有两个构造方法

构造方法备注
FileInputStream(File file)利用 File 构造文件输入流
FileInputStream(String name)利用文件路径构造文件输入流

而这两个构造方法其实都是一个意思, 如下图, 参数是 String 的构造方法会根据这个 String 先创建 File 对象, 再把 File 对象传入另一个构造方法, 本质上都是先创建一个File对象, 再进行其余的步骤

在这里插入图片描述

这是 InputStream 中的常用方法

返回值方法签名备注
intread()读取一个字节的数据,如果读完返回-1
intread(byte[] b)将读取到的数据存入b中, 返回实际读到的数量;实际读取到的字节数不超过b.length, 如果读完返回-1
intread(byte[] b,int off, int len)b数组从 off 开始将读取的数据存入b中,返回实际读到的数量, b数组满了就不读了;返回 -1 代表读完了
voidclose()关闭字节流

需要注意的时候, 如果文件内容分多次读取数据, 每次读取任务完成后, 都会记录光标位置(也就是记录这次读到哪了), 下次读取数据的时候再从这个位置开始读取, 而不是每次都重新读

例如, 如果某一次读取到如下 o 字符前面的 w 就结束了本次读取, 则会记录本次读取到的位置, 那么下次读取的时候再从 o 开始读取

在这里插入图片描述

InputStream 的 读取操作有三个read方法,

我在 D 盘中创建了 text.txt 文件, 里面有"hello world" , 以此举例子

第一种 | read()
public static void main(String[] args) throws IOException {
        InputStream inputStream = new FileInputStream("D:/text.txt");
        while (true) {
            int b = inputStream.read();
            if (b == -1) {
                break;
            }
            System.out.print(b + "   ");
        }
        inputStream.close();
    }

第一种就是一个字节一个字节的读, 整形 b 则是字节对应的值, 如下图, text.txt 的内容是"hello world", 转化成对应的整形就是以下输出。

在这里插入图片描述

第二种 | read(byte[] b)
	public static void main(String[] args) throws IOException {
        InputStream inputStream = new FileInputStream("D:/text.txt");

        byte[] buf = new byte[500];
        int ret = inputStream.read(buf); //接收实际读取到的字节数
        for (int i = 0; i < ret; i++) {
            System.out.print(buf[i] + "   ");
        }

        inputStream.close();
    }

第二种 : 将读到的数据存在 byte[] 中, 相比第一种方法, 第二种方法更加高效。假设我要买50个鸡蛋, 方法一就是跑到超市买一个鸡蛋, 然后回家, 买50次。方法二就是提一个大包去超时买50个, 然后回家。实际上, 这个 byte[] 也是起到了缓冲区的作用, 减少了很多"路程"上的资源消耗。

如下, 和上述方法一样的输出

在这里插入图片描述第三种 read(byte[] b, int off, int end) 本质上和 第二种是差不多的, 这里不赘述了。

OutputStream | 输出流

OutputStream 和 InputStream 一样, 都是抽象类, 今天重点还是它的实现类 FileOutputStream

OutputStream 的构造方法和 InputStream 大同小异, 两个构造方法本质是一样的, 也是先创建 File 对象, 再以这个为对象为参数进入另一个构造方法

在这里插入图片描述
关于OutputStream 中常用的方法

返回值方法签名说明
voidwrite(int b)写入参数数据
voidwrite(byte[]b)将 b 这个字符数组中的数据全部写入
intwrite(byte[]b, int off,int len)将 b 这个字符数组中从 off 开始的数据写入,一共写 len 个
voidclose()关闭字节流
voidflush()刷新此输出流并强制任何缓冲的输出字节被写出

这里说一下 flush 方法, 由于 IO 操作的速度慢, 大多数的 OutputStream 是有缓冲区的, 啥意思呢 ? 就是 大多 IO 操作的数据会先放在缓冲区中, 直到缓冲区满了, 或者达到某个条件之后, 才会将缓冲区的全部写入。所以有时候我们写入的数据还停留在缓冲区中, 就需要我们及时 flush , 将缓冲区的数据移道它该去的地方。

第一种 | write(int b)
    public static void main(String[] args) throws IOException {
        OutputStream outputStream = new FileOutputStream("D:/text.txt");
        outputStream.write(97);

        outputStream.close();
    }

第一种, 将参数写入, 且参数为 int, 运行结果如下, 97对应的字符就是 ‘a’

在这里插入图片描述这种情况在向文件写入数据的时候, 都会先将文件的数据清空, 再进行写入。

并且, 整形参数只有低8位会被写入, 高24位会被忽略

第二种 | write(byte[] b)
    public static void main(String[] args) throws IOException {
        OutputStream outputStream = new FileOutputStream("D:/text.txt");
        String str = "hello";
        byte[] buf = str.getBytes();
        for (int i = 0; i < buf.length; i++) {
            outputStream.write(buf[i]);
        }

        outputStream.close();
    }

如上, 把 "hello"转化成对应的 byte[] 数组, 再进行写入

在这里插入图片描述

对于输出流也是一样, 如果多次对同一个文件进行写入, 每次写入都会更新光标位置, 下一次写入就从光标位置开始继续写入, 当然光标的位置也可以进行手动调整。

同样对于write(byte[] b, int off, int len) 也是差不多的, 这里不赘述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

答辣喇叭

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

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

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

打赏作者

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

抵扣说明:

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

余额充值