目录
文件
文件路径
文件类型
Java 文件操作
文件系统操作
文件内容操作
字节流
InputStream
OutputStream
字符流
Reader
Writer
补充
close 的必要性
Scanner 的基本了解
文件
- 当前指硬盘上的文件和文件夹
- 相对于 变量 在内存中,文件 则是在硬盘上
文件路径
- 每个文件在硬盘上均有一个具体的路径
实例:
注意:
- 正斜杠 " / " 和 反斜杠 " \ " 均可以用来表示路径
- 推荐优先使用正斜杠 " / "
- 当在代码中写文件路径时,使用反斜杠 " \ " 可能会导致 文件路径 部分变为 转义字符 的现象
两种路径表示
- 绝对路径:以 盘符 开头的路径
- 相对路径:以当前所在的目录(工作目录)为基准,以 . 或者 .. 开头,来找到指定路径( . 有时候可省略)
实例:
- IDEA 的工作路径默认为当前项目所在目录
文件类型
- word、exe、图片、视频、音频、源代码、动态库 ......
文本文件
- 存 文本 和 字符串
- 字符串 由 字符 构成,每个字符均通过一个数字表示,该文本文件中存的数据,必须是指定字符编码的码表内的数据
二进制文件
- 存二进制数据数据,可存储任何数据,无文本文件的限制!
区分文件:
- 使用 记事本 打开该文件
- 记事本 出现乱码,则为 二进制文件
- 记事本 无乱码,则为 文本文件
Java 文件操作
文件系统操作
- 文件的创建、删除、重命名......
File 中的静态变量 pathSeparator 由系统决定 代指 " / " 或 " \ "
File 中的构造方法 File(File parent, Sting child) 根据 父目录 + 孩子文件路径,创建 File 实例(可为绝对路径或相对路径) File(String parent, Sting child) 根据 父目录路径 + 孩子文件路径,创建 File 实例(可为绝对路径或相对路径) File(File pathname) 根据 文件路径创建一个 File 实例,路径可以是绝对路径或相对路径
通常使用红色标注的构造方法
File 中的常见方法
package io; import java.io.File; import java.io.IOException; public class IODemo1 { public static void main(String[] args) throws IOException { // 这里随便创建一个 File对象 File file = new File("./test.txt");//File() 中的路径不要求真实存在 // 打印 file 的文件名 System.out.println(file.getName()); // 打印 file 的父级路径 System.out.println(file.getParent()); // 打印 file 的完整路径 System.out.println(file.getPath()); // 打印 file 的绝对路径 System.out.println(file.getAbsolutePath()); // 打印 file 绝对路径的简化路径 System.out.println(file.getCanonicalPath()); } }
运行结果:
package io; import java.io.File; import java.io.IOException; public class IODemo2 { public static void main(String[] args) throws IOException { // 这里创建一个 File对象 File file = new File("./test.txt");//File() 中的路径不要求真实存在 // file对象在真实的硬盘路径上并不存在,从而可以通过该方法根据file的路径创建一个新文件 file.createNewFile(); // 打印 file 是否存在 System.out.println(file.exists()); // 打印 file 是否为普通文件 System.out.println(file.isFile()); // 打印 file 是否为目录 System.out.println(file.isDirectory()); } }
运行结果:
package io; import java.io.File; public class IODemo3 { public static void main(String[] args) { // 这里创建一个 File对象 File file = new File("./test.txt");//File() 中的路径不要求真实存在 // 将文件从硬盘中删除 file.delete(); // 根据 File 对象,标注文件将被删除,删除动作会到 JVM 运行结束时才会进行 // 也就是该删除 是在程序退出的时候自动删除,比如程序中需要使用到一些 "临时文件" 的时候,会用到 // file.deleteOnExit(); } }
运行结果:
package io; import java.io.File; public class IODemo4 { public static void main(String[] args) { // 这里创建一个 File对象 File dir1 = new File("./test1");//File() 中的路径不要求真实存在 // 根据 dir路径 创建一个目录,仅能创建一级目录 dir1.mkdir(); // 这里创建一个 File对象 File dir2 = new File("./test2/aaa/bbb");//File() 中的路径不要求真实存在 // 根据 dir路径 创建一个目录,可创建多级目录 dir2.mkdirs(); } }
运行结果:
package io; import java.io.File; public class IODemo5 { public static void main(String[] args) { // 这里创建一个 File对象 File file = new File("./test2"); File test = new File("./test333"); // 使用该方法对 file 进行重命名 file.renameTo(test); } }
运行结果:
文件内容操作
- 就是文件的读和写
- InputStream 、 Reader、OutputStream 、 Writer 均为抽象类不能直接 new
四大操作
- 打开文件(构造对象)
- 关闭文件(close)
- 读文件(InputStream 和 Reader)
- 写文件(OutputStream 和 Writer)
字节流
- 操作二进制数据
InputStream
package io; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; public class IODemo6 { public static void main(String[] args) throws IOException { // 创建 InputStream对象 时,使用绝对路径 或 相对路径 均可,也可使用 File对象 // 此处的 InputStream 为抽象类,当我们创建对象时,需指定一个具体实现类 // 此处我们关注文件的读取,从而使用 FileInputStream类 InputStream inputStream = new FileInputStream("d:/test.txt"); // 进行读操作 while (true) { // read方法 无参数,一次读一个字节 // read方法 一个参数,把读到的内容填充到参数的字节数组中(此处的参数为输出型参数)返回值是实际读取的字节数 // read方法 三个参数,往数组的一部分区间中尽可能填充 // 此处 read方法读取一个字节,按照道理应该返回 byte类型,但是 read方法 却返回 int类型 // 因为除了返回 byte中所表示的 00000000~11111111 这些情况外,还需要有读取文件结束的标志 // 从而这里使用 -1 来表示读到文件末尾,从而使用 int类型 来返回 int b = inputStream.read(); if (b == -1) { // 读取完毕 break; } // 此处使用 16进制将每个字节打印出来 System.out.printf("%x\n",(byte)b); } // 最后需关闭文件 inputStream.close(); } }
运行结果:
package io; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class IODemo7 { public static void main(String[] args) throws IOException { InputStream inputStream = new FileInputStream("d:/test.txt"); // 进行读操作 while (true) { // read方法 无参数,一次读一个字节 // read方法 一个参数,把读到的内容填充到参数的字节数组中(此处的参数为输出型参数)返回值是实际读取的字节数 // read方法 三个参数,往数组的一部分区间中尽可能填充 // 即先准备好一个数组 byte[] buffer = new byte[1024]; // 正因为往 read方法中传入 buffer 这个参数,所以才能让 read方法内部针对 buffer数组进行填写,从而此处的参数为 输出型参数 // 这里与之前Java一般传参场景是不同的,习惯的是将输入的信息作为参数,输出的信息作为返回值 // 而此处是使用参数来返回内容 int len = inputStream.read(buffer); // 虽然 buffer数组 的长度为1024,但当实际上文件的长度是有限的,如果剩余长度超过1024,此时 1024个字节都会填满,则返回值len为1024 // 但是如果当前剩余长度不足1024,此时有多少 read方法就往 buffer数组中填多少,则返回值len 为实际读取的长度 // 当然如果读完了,此时 read方法 继续读,但读不到一个字节,则返回值len为-1,表示文件已经读完了! System.out.println("len:" + len); if (len == -1) { // 读取完毕 break; } // 此处使用 16进制将每个字节打印出来 for (int i = 0; i < len; i++) { System.out.printf("%x\n",buffer[i]); } } // 最后需关闭文件 inputStream.close(); } }
运行结果:
注意:
- buffer 译为缓冲区,其存在的目的就是为了提高 IO操作 的效率
- 单次 IO操作,是要访问 硬盘 / IO设备 ,单次操作比较耗时间的且时长固定,频繁进行 IO操作,其总耗时也相应增加
- 从而减少 IO操作 的次数,便可以提高程序整体的效率
- 从而引入 buffer 使 read方法 一次读多个字节,便有效降低了循环次数,也就是IO操作的次数
OutputStream
package io; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class IODemo8 { // 进行写文件 public static void main(String[] args) throws IOException { try(OutputStream outputStream = new FileOutputStream("d:/test.txt")) { // 默认情况下,outputStream 打开一个文件,会先清空文件原有的内容 outputStream.write(97); outputStream.write(98); outputStream.write(99); outputStream.write(100); } // 关闭文件 // outputStream.close(); 该行代码由 try语句块 自动实现 // 上述代码加入 try语句块 的目的就是为了能够确保 文件的关闭,也就是 close() 方法的执行 // 之所以无显示的写 close() 方法,是因为该 try语句块 在 JAVA 中称为 try with resources 语法 // 该语法只要 try语句块 执行完毕,就可以自动执行到 close() 方法 } }
运行结果:
字符流
- 操作文本数据
Reader
package io; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.Reader; public class IODemo9 { // 字符流操作 public static void main(String[] args) throws IOException { Reader reader = new FileReader("d:/test.txt"); while(true){ int ch = reader.read(); if (ch == -1) { break; } System.out.println("" + (char) ch); } } }
运行结果:
Writer
package io; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; public class IODemo10 { public static void main(String[] args) throws IOException { try (Writer writer = new FileWriter("d:/test.txt")){ // 默认情况下,writer 打开一个文件,会先清空文件原有的内容 writer.write("hello world"); // 像这样的写操作,其实是先写到缓冲区中,自己代码可有缓冲区、标准库有缓冲区、操作系统内核有缓冲区 等 // 当写操作执行完了,内容可能在缓冲区中,还未真正进入硬盘 // 此时 close 操作就会触发缓冲区的冲刷操作(将缓冲区中的内容写到硬盘中) // 当然使用 close 后文件将会直接关闭,从而无法继续对文件进行操作 // 使用 flush 可以手动冲刷缓冲区,且还能继续对文件进行操作 // 手动冲刷缓冲区 writer.flush(); } } }
运行结果:
补充
close 的必要性
Scanner 的基本了解
package io; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Scanner; public class IODemo11 { public static void main(String[] args) { // 这里的 System.in 是一个输入流对象,指向标准输入 // 从而这里的 scanner 便从键盘读取 // Scanner scanner = new Scanner(System.in); // 当然我们也可以在 使 scanner 读取文件,仅需更换传入的流对象,传入文件流对象即可 try (InputStream inputStream = new FileInputStream("d:/test.txt") ){ Scanner scanner = new Scanner(inputStream); // 此时这里的 scanner 就是从 文件 进行读取 scanner.next(); } catch (IOException e) { e.printStackTrace(); } // 注意实际上 scanner 的 close 本质上是要关闭内部包含的这个流对象 // 但是 其内部的 inputStream对象 已经被 try() 关闭了,从而在里面的 scanner 不关闭 也没关系 } }