计算机中的文件
什么是文件?
在我们日常生活中,我们认为文件就是记录着一些信息的本子。这些本子上可以记录任何我们想记录的信息。并且我们可以将多个本子夹在一起,形成一个大的文件夹。
那么计算机也是如此,在计算机中也可以通过类似我们生活中这样的方式来形成一个记录有效信息的文件。
文件的分类(日常生活中):
操作系统中还会使用文件来描述一些硬件设备或软件资源:例如网卡、键盘、显示器
文件的分类(程序员的角度):
1.文本文件:后缀名为.c、.java、.txt等等文件
2.二进制文件:后缀名为.jpg、.doc、.ppt、.class等等文件
如何区分二进制文件和文本文件:
最简单的办法就是用记事本将这个文件打开,如果里面的内容是乱码就是二进制文件,不是乱码说明就是文本文件。
目录结构:n叉树
文件的路径
知道什么是文件后,那么怎么找到相应的文件呢?
有两种方法:
- 一种是通过绝对路径进行查找
- 一种是通过相对路径进行查找
绝对路径:以盘符开头的路径
例如:
以上就是以C盘为开头的路径
相对路径:按照树形结构来看,以任意结点为基准路径开始进行寻找,最终找到目标的路径
那么首先就要有一个基准路径,对于用命令行编程来说基准路径就是执行命令所在的目录
如果是在IDEA上,基准路径就是项目所在的位置
例如:../windows/progro/aa.txt
其中.代表当前结点,也就是基准结点
..代表当前节点的父节点,也就是基准目录的上一个目录
在java中操作文件
java操作文件:主要包括文件系统和文件内容两个操作
![]()
Java 中提供了 java.io.File 类来完成上述操作。
我们先来看看 File 类中的常见属性、构造方法和方法
属性
修饰符及类型 属性 说明 static String pathSeparator 依赖于系统的路径分隔符,String 类型的表示 static char pathSeparator 依赖于系统的路径分隔符,char 类型的表示 构造方法
签名 说明 File(File parent, String
child)根据父目录 + 孩子文件路径,创建一个新的 File 实例 File(String pathname) 根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者
相对路径File(String parent, String
child)根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用
路径表示方法
修饰符及返回
值类型方法签名 说明 String getParent() 返回 File 对象的父目录文件路径 String getName() 返回 FIle 对象的纯文件名称 String getPath() 返回 File 对象的文件路径 String getAbsolutePath() 返回 File 对象的绝对路径 String getCanonicalPath() 返回 File 对象的修饰过的绝对路径 boolean exists() 判断 File 对象描述的文件是否真实存在 boolean isDirectory() 判断 File 对象代表的文件是否是一个目录 boolean isFile() 判断 File 对象代表的文件是否是一个普通文件 boolean createNewFile() 根据 File 对象,自动创建一个空文件。成功创建后返
回 trueboolean delete() 根据 File 对象,删除该文件。成功删除后返回 true void deleteOnExit() 根据 File 对象,标注文件将被删除,删除动作会到
JVM 运行结束时才会进行String[] list() 返回 File 对象代表的目录下的所有文件名 File[] listFiles() 返回 File 对象代表的目录下的所有文件,以 File 对象
表示boolean mkdir() 创建 File 对象代表的目录 boolean mkdirs() 创建 File 对象代表的目录,如果必要,会创建中间目
录boolean renameTo(File
dest)进行文件改名,也可以视为我们平时的剪切、粘贴操
作boolean canRead() 判断用户是否对文件有可读权限 boolean canWrite() 判断用户是否对文件有可写权限 了解一下分隔符:
在java中,一个文件路径是通过分隔符将每一个目录文件分开的
- 一般输入时可以使用 / 或 \
- 但输出时都以 \ 输出
使用File类来创建一个file实例,定位到指定文件夹:
- 使用绝对路径
- 使用相对路径
1.使用绝对路径:
2.使用相对路径:
调用File类的get基本方法:
普通文件的创建:
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.exists());System.out.println(file.isDirectory());System.out.println(file.isFile());System.out.println(file.createNewFile());System.out.println(file.exists());System.out.println(file.isDirectory());System.out.println(file.isFile());System.out.println(file.createNewFile());} }运行结果: false false false true true false true false
普通文件的删除:
import java.io.File;import java.io.IOException; public class Main {public static void main(String[] args) throws IOException {File file = new File("some-file.txt"); // 要求该文件不存在,才能看到相同的现象System.out.println(file.exists());System.out.println(file.createNewFile());System.out.println(file.exists());System.out.println(file.delete());System.out.println(file.exists());} }运行结果: false true true true false
创建目录:
文件重命名:
import java.io.File;import java.io.IOException; public class Main {public static void main(String[] args) throws IOException {File file = new File("some-file.txt"); // 要求 some-file.txt 得存在,可以是普通文件,可以是目录File dest = new File("dest.txt"); // 要求 dest.txt 不存在System.out.println(file.exists());System.out.println(dest.exists());System.out.println(file.renameTo(dest));System.out.println(file.exists());System.out.println(dest.exists());} }运行结果: true false true false true
以上是针对文件系统的一些操作
对于文件内容的操作,java标准库提供了一组类:
InputStream和FileInputStream概述:
InputStream方法:
修饰符及
返回值类
型方法签名 说明 int read() 读取一个字节的数据,返回 -1 代表已经完全读完了 int read(byte[] b) 最多读取 b.length 字节的数据到 b 中,返回实际读到的数
量;-1 代表以及读完了int read(byte[] b,
int off, int len)最多读取 len - off 字节的数据到 b 中,放在从 off 开始,返
回实际读到的数量;-1 代表以及读完了void close() 关闭字节流
![]()
FileInputStream构造方法:
签名 说明 FileInputStream(File file) 利用 File 构造文件输入流 FileInputStream(String name) 利用文件路径构造文件输入流
使用inputStream的read方法读文件:第一种read方法(一个字节一个字节读)
public static void main(String[] args) {// 构造方法中需要指定打开文件的路径.// 此处的路径可以是绝对路径, 也可以是相对路径, 还可以是 File 对象InputStream inputStream = null;try {// 1. 创建对象, 同时也是在打开文件.inputStream = new FileInputStream("d:/test.txt");// 2. 尝试一个一个字节的读, 把整个文件都读完.while (true) {int b = inputStream.read();if (b == -1) {// 读到了文件末尾break;}System.out.println(b);}} catch (IOException e) {e.printStackTrace();} finally {// 3. 读完之后要记得关闭文件, 释放资源~try {inputStream.close();} catch (IOException e) {e.printStackTrace();}} }
![]()
问题:如果在执行read时抛出异常了,就可能导致close关闭不了。
解决办法:把close放进finally里
优化:
![]()
使用第二种read方法读文件:效率更高
try (InputStream inputStream = new FileInputStream("d:/test.txt")) {// 一次读取若干个字节.while (true) {byte[] buffer = new byte[1024];int len = inputStream.read(buffer);if (len == -1) {// 如果返回 -1 说明读取完毕了break;}for (int i = 0; i < len; i++) {System.out.println(buffer[i]);}}} catch (IOException e) {e.printStackTrace();} }
使用Scanner类来进行读:按字符进行数据读
构造方法 说明 Scanner(InputStream is, String charset) 使用 charset 字符集进行 is 的扫描读取 示例代码:
import java.io.*;import java.util.*; // 需要先在项目目录下准备好一个 hello.txt 的文件,里面填充 "你好中国" 的内容 public class Main {public static void main(String[] args) throws IOException {try (InputStream is = new FileInputStream("hello.txt")) {try (Scanner scanner = new Scanner(is, "UTF-8")) {while (scanner.hasNext()) {String s = scanner.next();System.out.print(s);}}}} }
OutputStream概述:OutputStream方法:
修饰
符及
返回
值类
型方法签名 说明 void write(int b) 写入要给字节的数据 void write(byte[]
b)将 b 这个字符数组中的数据全部写入 os 中 int write(byte[]
b, int off,
int len)将 b 这个字符数组中从 off 开始的数据写入 os 中,一共写 len 个 void close() 关闭字节流 void flush() 重要:我们知道 I/O 的速度是很慢的,所以,大多的 OutputStream 为
了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的
一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写
入设备中,这个区域一般称为缓冲区。但造成一个结果,就是我们写的
数据,很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置,
调用 flush(刷新)操作,将数据刷到设备中
使用OutputStream的write方法进行写文件:
package file;import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream;// 使用字节流, 写文件的案例. public class Demo9 {public static void main(String[] args) {try (OutputStream outputStream = new FileOutputStream("d:/test.txt")) { // outputStream.write(97); // outputStream.write(98); // outputStream.write(99);byte[] buffer = new byte[]{97, 98, 99};outputStream.write(buffer);} catch (IOException e) {e.printStackTrace();}} }
![]()
使用Print进行写:按字符进行数据写
OutputStreamWriter osWriter = new OutputStreamWriter(os, "utf-8"); // 告诉它,我们的字符集编码是 utf-8 的PrintWriter writer = new PrintWriter(osWriter); // 接下来我们就可以方便的使用 writer 提供的各种方法了writer.print("Hello");writer.println("你好");writer.printf("%d: %s\n", 1, "没什么"); // 不要忘记 flushwriter.flush();
示例代码:
import java.io.*; public class Main {public static void main(String[] args) throws IOException {try (OutputStream os = new FileOutputStream("output.txt")) {try (OutputStreamWriter osWriter = new OutputStreamWriter(os, "UTF- 8")) {try (PrintWriter writer = new PrintWriter(osWriter)) {writer.println("我是第一行");writer.print("我的第二行\r\n");writer.printf("%d: 我的第三行\r\n", 1 + 1);writer.flush();}} } } }
flush方法:
小程序练习:
1.扫描目录:扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包含目录),并且后续询问用户是否要删除该文件。
完整代码:
package file;import java.io.File; import java.io.IOException; import java.util.Scanner;// 案例1, 实现查找文件并删除 public class Demo12 {public static void main(String[] args) {// 1. 先输入要扫描的目录, 以及要删除的文件名Scanner scanner = new Scanner(System.in);System.out.println("请输入要扫描的路径: ");String rootDirPath = scanner.next();System.out.println("请输入要删除的文件名: ");String toDeleteName = scanner.next();File rootDir = new File(rootDirPath);if (!rootDir.isDirectory()) {System.out.println("输入的扫描路径有误!");return;}// 2. 遍历目录, 把 指定目录 中的所有文件和子目录都遍历一遍, 从而找到要删除的文件// 通过这个方法来实现递归遍历并删除的操作scanDir(rootDir, toDeleteName);}private static void scanDir(File rootDir, String toDeleteName) {// 1. 先列出 rootDir 中都有哪些内容File[] files = rootDir.listFiles();if (files == null) {// rootDir 是一个空目录return;}// 2. 遍历当前列出的这些内容. 如果是普通文件, 就检测文件名是否是要删除的文件.// 如果是目录, 就递归的进行遍历for (File f : files) {if (f.isFile()) {// 普通文件的情况if (f.getName().contains(toDeleteName)) {// 不要求名字完全一样, 只要文件名中包含了关键字即可删除// 就进行删除操作deleteFile(f);}} else if (f.isDirectory()) {// 目录就递归的进行遍历scanDir(f, toDeleteName);}}}private static void deleteFile(File f) {try {System.out.println(f.getCanonicalPath() + " 确认要删除吗? (Y/n)");Scanner scanner = new Scanner(System.in);String choice = scanner.next();if (choice.equals("Y") || choice.equals("y")) {f.delete();System.out.println("文件删除成功!");} else {System.out.println("文件取消删除!");}} catch (IOException e) {e.printStackTrace();}} }
2.进行普通文件的复制:
完整代码:
package file;import java.io.*; import java.util.Scanner;public class Demo13 {public static void main(String[] args) {// 1. 输入两个路径Scanner scanner = new Scanner(System.in);System.out.println("请输入要拷贝的源路径: ");String src = scanner.next();System.out.println("请输入要拷贝的目标路径: ");String dest = scanner.next();File srcFile = new File(src);if (!srcFile.isFile()) {System.out.println("输入的源路径不正确!");return;}// 此处不太需要检查目标文件是否存在. OutputStream 写文件的时候能够自动创建不存在的文件.// 2. 读取源文件, 拷贝到目标文件中try (InputStream inputStream = new FileInputStream(src)) {try (OutputStream outputStream = new FileOutputStream(dest)) {// 把 inputStream 中的数据读出来, 写入到 outputStream 中byte[] buffer = new byte[1024];while (true) {int len = inputStream.read(buffer);if (len == -1) {// 读取完毕break;}// 写入的时候, 不能把整个 buffer 都写进去. 毕竟 buffer 可能是只有一部分才是有效数据.outputStream.write(buffer, 0, len);}}} catch (IOException e) {e.printStackTrace();}} }
3.扫描指定目录:并找到名称或者内容中包含指定字符的所有普通文件(不包含目录)
完整代码:
package file;import java.io.*; import java.util.Scanner;public class Demo14 {public static void main(String[] args) throws IOException {// 1. 输入要扫描的文件路径Scanner scanner = new Scanner(System.in);System.out.println("请输入要扫描的路径: ");String rootDirPath = scanner.next();System.out.println("请输入要查询的关键词: ");String word = scanner.next();File rootDir = new File(rootDirPath);if (!rootDir.isDirectory()) {System.out.println("输入的路径非法!");return;}// 2. 递归的进行遍历scanDir(rootDir, word);}private static void scanDir(File rootDir, String word) throws IOException {// 1. 先列出 rootDir 中都有哪些内容File[] files = rootDir.listFiles();if (files == null) {return;}// 2. 遍历每个元素, 针对普通文件和目录分别进行处理.for (File f : files) {if (f.isFile()) {// 针对文件进行内容查找if (containsWord(f, word)) {System.out.println(f.getCanonicalPath());}} else if (f.isDirectory()) {// 针对目录进行递归scanDir(f, word);}}}private static boolean containsWord(File f, String word) {// 写代码, 慎重使用缩写!!! 缩写的可读性会比较差. (一些业界常见缩写, 可以用, 不要随便滥用)StringBuilder stringBuilder = new StringBuilder();// 把 f 中的内容都读出来, 放到一个 StringBuilder 中try (Reader reader = new FileReader(f)) {char[] buffer = new char[1024];while (true) {int len = reader.read(buffer);if (len == -1) {break;}// 把这一段读到的结果, 放到 StringBuilder 中stringBuilder.append(buffer, 0, len);}} catch (IOException e) {e.printStackTrace();}// indexOf 返回的是子串的下标. 如果 word 在 stringBuilder 中不存在, 则返回下标为 -1return stringBuilder.indexOf(word) != -1;} }