目录
- 2.2 文件内容相关的操作
- 三、文件操作案例
- 3.1 案例一
- 3.2 案例二
- 3.3 案例三
2.2 文件内容相关的操作
- 打开文件
- 读文件
- 写文件
- 关闭文件
针对文件内容的读写,java标准库提供了一组类~
首先按照文件的内容,分为两个系列
- 字节流对象,针对二进制文件,是以字节为单位进行读写的,读:InputStream,写:OutputStream。
- 字符流对象,针对文本文件,是以字符为单位进行读写的,读:Reader,写:Writer。
InputStream
read提供了三个版本的重载
- 无参版本:一次读一个字节
- 一个参数版本:一次读若干个字节,把读的结果放到参数指定的数组中,返回值就是读到的字节数
- 三个参数版本:一次读若干个字节,把读的结果放到参数指定的数组中,返回值就是读到的字节数,不是从数组的起始位置放置,而是从中间位置放置(off这个下标的位置)len表示最多能放多少个元素(字节)
IO操作失败的可能性是非常大的,另外硬盘也容易出现“坏道”
package file;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
@SuppressWarnings({"all"})
public class Demo8 {
public static void main(String[] args) {
// 构造方法中需要指定打开文件的路径
try {
// 1. 创建对象,同时也是在打开文件
InputStream inputStream = new FileInputStream("d://tst.txt");
// 2. 尝试一个一个字节的读,把整个文件读完
while (true) {
int b = inputStream.read();
if (b == -1)
break;
System.out.println(b);
}
// 3. 读完之后要记得关闭文件,释放资源
inputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
更好的做法是把close放到finally里面
改进之后的代码
package file;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
@SuppressWarnings({"all"})
public class Demo8 {
public static void main(String[] args) {
// 构造方法中需要指定打开文件的路径
InputStream inputStream = null;
try {
// 1. 创建对象,同时也是在打开文件
inputStream = new FileInputStream("d://tst.txt");
// 2. 尝试一个一个字节的读,把整个文件读完
while (true) {
int b = inputStream.read();
if (b == -1)
break;
System.out.println(b);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
// 3. 读完之后要记得关闭文件,释放资源
try {
inputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
try (InputStream inputStream = new FileInputStream("d:/test.txt");){
while (true) {
int b = inputStream.read();
if (b == -1) {
break;
}
System.out.println(b);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
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) {
throw new RuntimeException(e);
}
OutputStream
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) {
throw new RuntimeException(e);
}
}
package file;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
@SuppressWarnings({"all"})
public class Demo10 {
public static void main(String[] args) {
try (Reader reader = new FileReader("d/test.txt")){
// 按照字符来读
while (true) {
char[] buffer = new char[1024];
int len = reader.read(buffer);
if (len == -1) {
break;
}
for (int i = 0; i < len; i++) {
System.out.println(buffer[i]);
}
String s = new String(buffer, 0, len);
System.out.println(s);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
package file;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
// 按照字符来写
@SuppressWarnings({"all"})
public class Demo11 {
public static void main(String[] args) {
try (Writer writer = new FileWriter("d:?test.txt")){
writer.write("xyz");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
三、文件操作案例
3.1 案例一
扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包含目录),并且后续询问用户是否要
删除该文件
用户输入一个目录~
再输入一个要删除的文件名~
package file;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
// 案例1 查找文件并删除
@SuppressWarnings({"all"})
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() + "确认要删除吗?");
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) {
throw new RuntimeException(e);
}
}
}
3.2 案例二
进行普通文件的复制
需要让用户指定两个文件路径
一个是原路径(被复制的文件)
一个是目标路径(复制之后生成的文件)
打开源路径的文件,读取里面的内容,并写入目标文件
package file;
import jdk.internal.util.xml.impl.Input;
import java.io.*;
import java.util.Scanner;
@SuppressWarnings({"all"})
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写进去,可能只有一部分是有效数据
outputStream.write(buffer, 0 , len);
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
3.3 案例三
扫描指定目录,并找到名称或者内容中包含指定字符的所有普通文件(不包含目录)
注意:我们现在的方案性能较差,所以尽量不要在太复杂的目录下或者大文件下实验
进行文件内容的查找
先输入一个路径
再输入一个要查找文件内容的”关键字“
递归遍历文件,找到看哪个文件里的内容包含了关键字,就把对应的文件路径打印出来
package file;
import java.io.*;
import java.util.Scanner;
@SuppressWarnings({"all"})
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) {
throw new RuntimeException(e);
}
// indexOf 返回的是子串的下标,如果word 再stringBuilder中不存在就返回-1
return stringBuilder.indexOf(word) != -1;
}
}