文件(File)
狭义的文件: 指的是硬盘上的文件和目录
广义的文件: 泛指计算机中很多软硬件资源(操作系统中把很多硬件和软件资源抽象成了文件, 按照文件的方式同意管理)
本章内容只讨论狭义的文件
路径
- 绝对路径: 以c: , d: 盘符开头的路径
- 相对路径: 以当前所在的目录为基准(工作目录), 以. 或 … 开头(有时 . 可以省略), 找到指定的路径
那么我们的IDEA的工作路径在哪呢?
IDEA 的工作路径默认就是在当前的项目所在目录
Java 对于文件的操作
- 针对文件系统操作(文件的创建, 删除, 重命名)
- 针对文件内容的操作(文件的读和写)
Java 标准库中提供了File这个类
parent 表示当前文件所在目录
child 表示自身的文件名
File file = new File("d:/text.txt");
构建一个File 对象
import java.io.File;
import java.io.IOException;
public class IODemo1 {
public static void main(String[] args) throws IOException {
File file = new File("./test1.txt");
// 获取文件名
System.out.println(file.getName());
// 获取父级路径
System.out.println(file.getParent());
// 获取完整路径
System.out.println(file.getPath());
// 获取绝对路径
System.out.println(file.getAbsoluteFile());
// 获取绝对路径的简化路径
System.out.println(file.getCanonicalPath());
}
}
判断文件
import java.io.File;
public class IODemo2 {
public static void main(String[] args) {
File file = new File("d:/f1/f2/test1.txt");
// 这个文件是否存在
System.out.println(file.exists());
// 这是不是一个文件
System.out.println(file.isFile());
// 这是一个目录吗
System.out.println(file.isDirectory());
}
}
创建文件
import java.io.File;
import java.io.IOException;
public class ThreadDemo3 {
public static void main(String[] args) throws IOException {
File file = new File("./test.txt");
//创建这个文件
file.createNewFile();
}
}
删除文件
import java.io.File;
public class IODemo4 {
public static void main(String[] args) {
File file = new File("./test.txt");
// 删除文件
file.delete();
}
}
deleteOnExit
import java.io.File;
import java.io.IOException;
public class IODemo5 {
public static void main(String[] args) throws IOException {
File file = new File("test.txt");
System.out.println(file.exists());
System.out.println(file.createNewFile());
System.out.println(file.exists());
//程序运行结束后删除
file.deleteOnExit();
System.out.println(file.exists());
}
}
目录的创建
import java.io.File;
public class IODemo6 {
public static void main(String[] args) {
File dir = new File("d:/f1/f2/f3/f3");
dir.mkdir(); // 只能创建一级目录
dir.mkdirs(); // 创建多级目录
}
}
文件的重命名
import java.io.File;
public class IODemo7 {
public static void main(String[] args) {
File file = new File("./aaa/bbb/test.txt");
File file1 = new File("./aaa/bbb/test2.txt");
file.renameTo(file1);
}
}
Java 标准库的流对象
从类型上分成两个大类
- 字节流: 操作二进制数据的
- 字符流: 操作文本数据
read 无参数版本:一次只读一个字节
read 有一个参数版本: 把读到的内容填充到参数的这个字节数组中, (此处的参数是一个输出型参数), 返回值是实际读取的字节数
read 有三个参数的版本: 和一个参数的差不多. 只不过是往数组的一部分区间里尽可能填充
思考:
read 读取的是一个字节, 按理说应该返回一个 byte , 但是实际上是返回int, 这是为什么呢?
这里除了表示byte里的0~255 (-128 ~ 127) 这样的情况外, 还需要表示一个特殊情况, -1,这个标记表示读取文件结束了(读到末尾了).
UTF-8 每个汉字三个字节
字节流读取:
import java.io.*;
public class IODemo8 {
// 使用字节流读取文件
public static void main(String[] args) throws IOException {
// 创建InputStream 对象的时候, 使用绝对路径或者相对路径都行, 也可以使用File对象
InputStream inputStream = new FileInputStream("d:/test.txt");
// //进行读操作
// while (true) {
// int b = inputStream.read();
// if(b == -1) {
// // 读取完毕
// break;
// }
// //System.out.println(""+ (byte)b);
// System.out.printf("%x",(byte)b);
// }
while (true) {
byte[] buffer = new byte[1024];
int len = inputStream.read(buffer);
System.out.println("len: "+ len);
if (len == -1) {
break;
}
// 此时读取的字符就被放到了byte[] 中了.
for (int i = 0; i < len; i++) {
System.out.printf("%x\n", (byte)buffer[i]);
}
}
inputStream.close();
}
}
buffer 存在的意义,是为了提高 IO 操作的效率,
单次 IO 操作, 是要访问硬盘的, 所以就会比较耗费时间,
缩短了 IO 操作的次数, 所以效率也就提高了
字节流写文件
也是类似的三个方法
public class IODemo9 {
// 进行写文件
public static void main(String[] args) throws IOException {
OutputStream outputStream = new FileOutputStream("d:/test.txt");
outputStream.write(97);
outputStream.write(98);
outputStream.write(99);
outputStream.write(100);
outputStream.close();
}
}
更推荐的写法
这个写法虽然没有显示的写 close , 但是在 try 语句执行完的时候, 会自动执行到 close
public class IODemo {
public static void main(String[] args) throws IOException {
try (OutputStream outputStream = new FileOutputStream("d:/test.txt")) {
outputStream.write(97);
outputStream.write(97);
outputStream.write(97);
outputStream.write(97);
outputStream.write(97);
outputStream.write(97);
}
}
}
字符流读文件
package io;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class IODemo10 {
// 字符流的操作
public static void main(String[] args) {
try (Reader reader = new FileReader("d:/test.txt")) {
while (true) {
int ch = reader.read();
if (ch == -1) {
break;
}
System.out.println("" + (char)ch);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
字符流写文件
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class IODemo11 {
// 字符流写文件
public static void main(String[] args) {
try (Writer writer = new FileWriter("d:/test.txt")) {
writer.write("hello world");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
下面我们实现一个删除文件的小程序
import java.io.File;
import java.util.Scanner;
public class IODemo12 {
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
// 让用户输入一个指定搜索的目录
System.out.println("请输入一个要搜索的路径: ");
String basePath = scanner.next();
// 针对用户输入进行简单判定,
File root = new File(basePath);
if (!root.isDirectory()) {
// 路径不存在, 或者是一个普通文件, 此时无法进行搜索
System.out.println("输入的路径有误");
return;
}
System.out.println("请输入要删除的文件名: ");
// 此处使用 next, 不用 next.Line
String nameToDelete = scanner.next();
// 针对指定路径进行扫描, 递归操作
// 先从根目录出发(root)
// 先看看这个目录是否有我们要删除的文件, 如果有就删除, 否则下一个
// 如果是包含了一些目录, 那就进行递归
scanDir(root,nameToDelete);
}
private static void scanDir(File root, String nameToDelete) {
// 1. 先列出当前路径下包含和目录
File[] files = root.listFiles();
if (files == null) {
// 当前目录没东西, 进行下一步递归
return;
}
// 遍历当前列出的结果
for (File f: files) {
if (f.isDirectory()) {
// 如果是目录就进一步递归
scanDir(f,nameToDelete);
} else {
// 如果是文件就判断
if (f.getName().contains(nameToDelete)) {
System.out.println("确认要删除 " + f.getName() + "吗?");
String choice = scanner.next();
if (choice.equals("Y") || choice.equals("y")) {
f.delete();
System.out.println("删除成功");
} else {
System.out.println("删除取消");
}
}
}
}
}
}
文件的复制
就是把一个文件按照字节一次读取, 把结果写入另一个文件中
import java.io.*;
import java.util.Scanner;
// 文件的拷贝
public class IODemo13 {
public static void main(String[] args) throws RuntimeException {
// 输入两个路径 一个源 一个目标路径 (从哪里拷贝到哪)
Scanner scanner = new Scanner(System.in);
System.out.println("请输入要拷贝哪个文件: ");
String srePath = scanner.next();
System.out.println("请输入要拷贝到哪个地方: ");
String destPath = scanner.next();
File srcFile = new File(srePath);
if (!srcFile.isFile()) {
System.out.println("您输入的源路径有误!");
return;
}
File destFile = new File(destPath);
if (destFile.isFile()) {
// 如果已经存在不能拷贝
System.out.println("您输入的目标路径有误: ");
return;
}
// 进行拷贝操作
try (InputStream inputStream = new FileInputStream(srcFile);
OutputStream outputStream = new FileOutputStream(destFile)) {
// 进行读文件操作
while (true) {
int b = inputStream.read();
if (b == -1) {
break;
}
outputStream.write(b);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}