目录标题
- 文件和目录
- File方法分类
- File
- 创建 删除 重命名 文件
- 首先是 创建 删除 重命名 文件 先创建一个File对象 并传入你要创建的文件完整路径 然后判断文件是否存在 当文件不存在时 调用createNewFile方法创建新文件 该方法有异常抛出 使用try-catch将其捕获 输出创建结果 例子编写完成
- 练习
- 接下来 重命名刚刚创建的新文件 当文件存在时 调用renameTo方法 重命名此文件 该方法需要传入一个File对象 File路径为新名称的路径 接收方法返回值 输出重命名结果 例子编写完成
- 注意(此处的创建是代替原来名字相同的文件 不是重新创建一个) !!! 观察执行结果
- 接下来 删除刚刚重命名的目录 当目录存在时 调用delete方法删除此目录 输出删除结果 例子编写完成 执行程序
- 重点! 从执行结果来看目录删除成功 但是注意 刚刚删除的目录是一个空目录 如果目录下还有文件或者目录的话 那么该目录是无法被删除的 想要被删除的话 必须将目录下所有文件(包括目录)清空
- 列出路径所有文件或目录
- 练习
- 创建多级目录
- 总结本节内容
- 字符是如何存储在电脑上的
- 字节输入流 InputStream
- 读取文件中的内容
- 我们可以借助InputStream旗下的子类 它和它的子类们都属于字节流 也就是按字节为单位读取数据的流 刚刚我们要读取的是文件数据 所以 选择FileInputStream 文件字节输入流
- 所以可以看出 它用于读取文本、图片、音乐、视频等文件数据
- 它一共有三个构造方法 你可以传一个文件路径 也可以传一个表示文件的File对象 这两个方法用得最多 也可以传一个文件描述符 这个构造方法几乎用不到 因为文件描述符 只能通过已经创建的流对象来获取
- 通过其read方法 每次只读一个字节 直到最后没有可读的字节 返回 -1 作为结束标识 read方法返回的类型 并不是byte 而是int
- 至于为什么 看下一个知识点 直接输出这些int值 得到的只是一些数字 这些数字就是字符所对应的字节值 对于字符而言 这些字节值就是码值 如果想要输出字符的话 需将其转换为char类型 然后就可以得到原来的字符
- 练习
- 编码练习 首先创建文件字节输入流 并传入文件路径 构造方法有异常抛出 使用try-catch将其捕获 然后调用read方法读取单个字节
- read方法有异常抛出 使用catch将其捕获 接着输出刚刚读取到的字节值 这里输出的是一个数字 不便于观看 我们可以将其转换为char类型 以字符形式输出
- 从执行结果来看 "a”是我们读取到的第一个字符 也是第一个字节 一行读一个 这种写法太低效 可以采用循环的方式来读 那循环什么时候结束呢
- 当我们读到字节值为-1的时候结束
- 这个程序还有更优的写法 可以将字节值定义在循环外 将读取字节的操作 和判断字节值是否为-1 写在循环条件中 这样的写法在实际开发中更为常见 从执行结果来看 文件中的每一个字节都读出来了
- 总结
- read方法读的是字节为什么返回int
- 在上一讲中 我们可以看到 read方法读的是字节返回的而是int 为什么read方法 返回的不是byte 而是int呢 这个和它的结束标识有关 也就是和这个 -1 有关
- 在Java中 一个数字的二进制位 最高位是符号位 0 代表的是正数 1 代表的是负数 但一个负数 远不是将最高位置于1这么简单 它是其正数的原码 取反得到反码 再 +1 得到补码 最后的补码 才是一个负数的二进制表现形式 这是 -1 的二进制
- 假设我们要读的文件中 正好有 -1 时 就无法判断 这是数据已经读完了 还是数据本身 就是 -1
- 因此设计者 将read方法 的返回值类型 设置为int 四个字节 16 位 目的就是为了 防止直接读到 -1
- 上方的字节值 是 255 想要原生的字节值时 只需再把它转为byte即可 高位全部去掉 只保留低 8 位 这样我们就得到了 原生数据 -1 以上就是 为什么read方法 返回int 的原因
- 总结
- 数据读取完以后为什么要关闭流?
- 数据读完以后 调用close方法关闭流
- 为什么一定要关闭流呢
- 例如: 例如 在删除电脑文件时 如果这个文件正在打开或者正在使用 电脑是不会执行这个步骤的 提示 该文件正在使用无法删除的情况 那么这个时候 就需要关闭正在使用的文件 释放资源 然后才可以删除 这个和我们关闭流是一个道理的
- 关闭流是一定要关闭的 但不是写在try代码块中 而是写在finally代码块中 这样 即使操作流的过程中发生异常 也会执行关闭流的操作 将创建流的操作 拆分为声明流 和初始化流 两部分 然后将关闭流的操作 移动到finally代码块中 在关闭流之前 先判断流是否为空 当流不为空时 再关闭流 close方法有异常抛出 使用try-catch将其捕获 到此 完整的输入流读取数据的书写格式就是下图三格式
- 重点! 一共有四步 第一步 : 声明流 第二部:初始化流 第三步: 读取数据 第四步:关闭流 从执行结果来看:改写后的程序没有任何问题 流关闭以后 就不能再读取数据了 否则就会发生io异常
- 总结:
- 如何更高效的读取字节
- 除了每次读取单个字节以外 我们还可以每次读取多个字节 以此来提升效率
- 批量读取的字节 都装在一个容器里 这个容器就是字节数组 数组大小可以自己拟定 如此以来 数组有多大 每次就能读多少
- 但是需要注意的是 数组是重复使用的 新读入的字节 会覆盖掉原来位置上的字节 这样就会产生 没覆盖全的情况 数组中还存在之前读入的字节 最后输出的结果 就会存在多余的字符 这个现象一会演示
- 下面演示一个批量读取字节的示例 按照上一节讲解的代码书写格式中 编写好基本代码 读取数据的部分 目前还没写 创建一个长度为4 的字节数组 循环批量读取字节 读到 -1 时结束 每次都以字符串形式输出 长度为 4 的数组 刚刚好 分两次读完 没有多余的字节
- 接下来 我们来演示 有多余字节的问题 基本代码一样! 只需将数组长度 由4 改为 3 这样就会出现多余的字符 多输出 一个 “f” 产生问题的原因 前面的内容已经讲解过了 问题也很好解决!!! 我们只需记录一下 read方法实际读入的字节数 在输出的时候 从下标 0 开始输出 输出的长度为实际读入的字节数 注意重点 : ((length = in.read(bytes)) != -1) 这样的话 便没有多余的字符了
- 总结:
- 什么是字节输出流OutputStream
- 它和输入流一样 也有一套体系 包括将数据输出到文件FileOutputStream 带缓冲区的 BufferedOutputStream 等其他一些输出流 其中最为常用的 就是 FileOutputStream
- 借助 FileOutputStream 我们可以向文件中写入数据 完成复制文件等操作
- FileOutputStream 一共有五个构造方法 其功能如下图所示 第一个参数 String name 创建文件输出字节流 并指定文件路径 默认覆盖文件 第二个参数 boolean append 创建文件输出字节流 并指定文件路径 是否追加文件 默认覆盖文件
- 下面 通过将一个字符串写入到文件中 来学习 输出流的基本知识 而这个过程 正好和读取字节相反
- 先根据编码表 找到字符所对应的十进制码值 再将码值 转换为 字节 转换为字节以后 再调用输出流的write方法 依次写入文件中
- 写入的方式有两种 一种是: 每次写入单个字节 还有一种是: 每次写入一个字节数组 后者效率更高
- 练习
- 下面我们就采用后者 来编写一份示例 首先声明一个输出流 然后初始化它 并传入你要输出的文件路径中
- 创建FileOutputStream时有异常抛出 使用try-catch 将其捕获 写上finally 代码块
- 在finally代码块中 调用close方法关闭流 在关闭流之前 先判断流是否为空 当流不为空时 再关闭流
- close方法有异常抛出 使用 try-catch 将其捕获
- 练习
- 重点!!! 最后 我们来编写 写入数据的部分 创建你要写入的数据 比如这里的 "二哥一直坚持abcdefgh" 然后调用其 getBytes方法 转为字节数组
- 因为写入数据必须按字节为单位 所以这里要转为 字节数组 接着 调用输出流的write方法 将字节数组 中的数据 写到文件中
- write方法有异常抛出 使用catch将其捕获 至此 写入数据的部分编写完成 整个例子也编写完成 执行程序观看
- 一般来说 程序没有报错 就说明 写入成功 再来查看文件 文件可以看出 程序运行成功!!!
- 注意点: 当我们初始化输出流的时候 这里的输出文件 是我本身 事先创建好了的!!! 如果文件没有事先创建好 还需要使用 file对象 来进行 创建!!!
- 在创建之前 无论文件是否存在 都要进行判断一下 文件的存在情况
- 养成习惯 因为在实际开发中 不可能还去看看 文件到底创建了没有 一个提示 重点注意
- 总结