目录
文件概念
文件路径
绝对路径
相对路径
文件类型
文本文件
二进制文件
Java中对文件的操作
对文件系统的操作
get相关方法
文件类型判断和创建
文件删除
文件目录的创建
文件重命名
对文件内容的操作
字符流(操作字符数据)
代码例子
删除文件
复制文件
文件概念
本文的文件只是侠义上的文件,就是文件夹和里面的文件。
多说情况下,文件更多的意思是一种软硬件资源的意思,比如网卡。
文件路径
文件路径要注意的是目录级别之间的分割符在Windows系统下既可以是 / 也可以是 \
建议使用 / 因为 \搭配其他字符有可能是转义字符的意思。
文件路径描述了文件的具体位置。
绝对路径
绝对路径是针对于整个文件系统来说的,描述的路径是从头到尾一个不落。
从D这个盘符开始,把保存这个haha.txt文件的文件夹全部指出来。
相对路径
以当前路径文基准,或者用 . 或者 .. 开头,找到的路径就是相对路径。
当前的路径就是工作路径。假设ATest就是一个工作路径 d:/ATest
想要找到工作路径下面的hello文件夹,就直接可以用 ./hello 表示 (./ 表示当前路径)
想要找到工作路径的上面的文件夹,../ATest 可以表示 (../ 表示当前路径的上一级)
文件类型
文件类型可以分成两类,一种是二进制文件,一种是文本文件。
文本文件
存的是二进制数据,记事本打开看不懂。
二进制文件
存的是字符串,用记事本打开可以看懂。
Java中对文件的操作
Java对于文件的操作可以分为两大类,对文件系统的操作和文件内容的操作。其中Java标准库提供了File这个类,用来操作文件。
对文件系统的操作
静态成员
构造方法
构造方法仅仅只是表示文件的路径,至于有没有这个文件它是不管的,也不会创建出一个文件。
常用的实例方法
方法 | 说明 |
String getParent()
| 判断用户是否对文件有可写权限 |
String getName()
| 判断用户是否对文件有可写权限 |
String getPath()
| 判断用户是否对文件有可写权限 |
String getAbsolutePath()
| 返回 File 对象的绝对路径 |
String getCanonicalPath()
| 返回 File 对象的修饰过的绝对路径 |
boolean exists()
| 判断 File 对象描述的文件是否真实存在 |
boolean isDirectory()
| 判断 File 对象代表的文件是否是一个目录 |
boolean isFile()
| 判断 File 对象代表的文件是否是一个普通文件 |
boolean createNewFile()
|
根据
File
对象,自动创建一个空文件。成功创建后返回 true
|
boolean 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()
| 判断用户是否对文件有可写权限 |
代码演示。
get相关方法
import java.io.File;
import java.io.IOException;
public class IODemo1 {
public static void main(String[] args) throws IOException {
File file = new File("D:/ATest/hello/haha.txt");
System.out.println("该文件的上级路径" + file.getParent());
System.out.println("该文件的名字" +file.getName());
System.out.println("该文件的路径" +file.getPath());
System.out.println("该文件的绝对路径" +file.getAbsolutePath());
System.out.println("该文件修饰过的绝对路径" +file.getCanonicalPath());
}
}
文件类型判断和创建
import java.io.File;
import java.io.IOException;
public class IODemo2 {
public static void main(String[] args) throws IOException {
// 这个文件是存在的
File file = new File("D:/ATest/hello/haha.txt");
System.out.println("文件是否存在:" + file.exists());
System.out.println("是文件夹吗:" + file.isDirectory());
System.out.println("是文件吗:" + file.isFile());
System.out.println("能创建出来吗:" + file.createNewFile());
}
}
文件删除
import java.io.File;
import java.io.IOException;
public class IODemo3 {
public static void main(String[] args) throws IOException {
// 该文件不存在
File file = new File("D:/ATest/hello/xixi.txt");
System.out.println("删除了吗:" + file.delete());
System.out.println("创建出来了吗:" + file.createNewFile());
System.out.println("删除了吗:" + file.delete());
System.out.println("创建出来了吗:" + file.createNewFile());
file.deleteOnExit();
}
}
文件目录的创建
import java.io.File;
public class IODemo4 {
public static void main(String[] args) {
// 该目录不存在
// 创建单个文件夹(绝对路径下)
File file = new File("D:/ATest/lala");
System.out.println("文件夹存在吗:" + file.exists());
System.out.println("创建成功了吗:" + file.mkdir());
System.out.println("文件夹存在吗:" + file.exists());
// 该目录不存在
// 创建多个文件夹(在相对路径下)
File file2 = new File("./Test/lulu");
System.out.println("文件夹存在吗:" + file2.exists());
System.out.println("创建成功了吗:" + file2.mkdirs());
System.out.println("文件夹存在吗:" + file2.exists());
}
}
文件重命名
// 文件重命名 文件和文件夹都可以
// 这里只测试文件夹
import java.io.File;
public class IODemo5 {
public static void main(String[] args) {
// 把刚才Test/lulu文件名改成 heihei
File file = new File("./Test/lulu");
File dest = new File("./Test/heihei");
System.out.println("被修改文件是否存在:" + file.exists());
System.out.println("不会重名吧::" + dest.exists());
System.out.println("修改成功了吗:" + file.renameTo(dest));
}
}
对文件内容的操作
对文件内容的操作有两大类,它们都是一种类似于水流的操作。文件内容就像水龙头里的水流,文件里的就是数据流。这两大类分别是字节流和字符流,操作也都是非常相像的。都是打开,关闭,读文件和写文件。此外,对于读和写通常会搞不清楚,通过这个图就能够更好的理解了。
字节流(操作二进制数据)
通过InputStream、FileInputStream来操作。
字节流读的过程:
打开
使用构造方法打开。
读+关闭
此时文件内容为
import java.io.*;
// 读文件
// 测试字节流
// InputStream
public class IODemo6 {
public static void main(String[] args) throws IOException {
// 创建FileInputStream时,使用相对路径和绝对路径都可以,也可以直接放File对象
// InputStream 只是一个抽象类,要使用还需要具体的实现类。
// 关于 InputStream 的实现类有很多,基本可以认为不同的输入设备都可以对应一个 InputStream类
// 我们现在只关心从文件中读取,所以使用FileInputStream
InputStream inputStream = new FileInputStream("D:/ATest/hello/haha.txt");
InputStream inputStream2 = new FileInputStream("D:/ATest/hello/haha.txt");
InputStream inputStream3 = new FileInputStream("D:/ATest/hello/haha.txt");
while(true) {
// 无参数版本的read()
// 这里的read()每次只会读一个字节
int b = inputStream.read();
if (b == -1) {
// 当读到文件末尾的时候返回-1
// 这也就是为什么返回值时int类型
// 如果是byte的话,无法有多的部分表示 -1
break;
}
System.out.printf("%x ", (byte)b);
}
System.out.println();
System.out.println();
while (true) {
// 带有一个参数的read()
// 这个数组目的是为了返回数据
byte[] arr1 = new byte[20];
// 这里的read()读取的数据会尽可能的填满整个数组
// 如果文件内容不足以填满整个数组,此时返回的是实际长度
// 然后继续接着读(已到末尾),返回-1 (就是代码这里的情况 4<20)
// 如果读取完文件还有剩余(意味着数组被填满了, 就先返回实际长度)
// 然后继续读,并且会覆盖之前数组的值
// 直到文件读完了,就返回 -1
int len = inputStream2.read(arr1);
System.out.println("len : " + len);
if (len == -1) {
break;
}
// 读出来的放到arr1数组中
for (int i = 0; i < len; i++) {
System.out.printf("%x ", arr1[i]);
}
System.out.println();
}
System.out.println();
while (true) {
// 带有三个参数的read()
byte[] arr2 = new byte[20];
int off = 0;
// 存到数组下标为off的位置,每次存 4 个
int len = inputStream3.read(arr2, 0, 4);
System.out.println("len : " + len);
if (len == -1) {
break;
}
for (int i = off; i < len; i++) {
System.out.printf("%x ", arr2[i]);
}
System.out.println();
}
// 最后要关闭资源。否则会一直保存在pcb的文件资源描述符里
// 另外close方法还可以把缓冲区里的数据冲刷到内存中,与flush方法效果一样
inputStream.close();
inputStream2.close();
inputStream3.close();
}
}
字节流写的过程
打开
使用构造方法打开
写+关闭
此时文件的内容为
// 写文件
// 测试字节流
// OutPutStream
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class IODemo7 {
public static void main(String[] args) throws IOException {
// 打开方法于InPutStream一样 // OutputStream打开一个文件,默认会清空原先文件内容
OutputStream outputStream = new FileOutputStream("D:/ATest/hello/haha.txt");
// 从头写 -> a
outputStream.write(97);
// a -> abcd
byte[] arr1 = {98, 99, 100};
outputStream.write(arr1);
// abcd -> abcdgh
// e f g h i
byte[] arr2 = {101, 102, 103, 104, 105};
// 从数组下标的2位置开始,写2个数据进去
outputStream.write(arr2, 2, 2);
// 最后记得关闭
outputStream.close();
}
}
若是不想清空原文件的内容,在构造方法上改一下即可。
// 写文件
// 测试字节流
// OutPutStream
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class IODemo8 {
public static void main(String[] args) throws IOException {
// true 表示在该文件内容后面追加写 原内容:abcdgh
OutputStream outputStream = new FileOutputStream("D:/ATest/hello/haha.txt", true);
outputStream.write(97);
outputStream.write(98);
outputStream.write(99);
outputStream.close();
}
}
字符流(操作字符数据)
通过Reader和Writer来操作。(操作和InPutStream、OutPutStream基本完全一致);
读
// 读文件
// 测试字符流
// Reader
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class IODemo9 {
public static void main(String[] args) throws IOException {
// 和InPutStream一样 内容:abcdghabc
// 因为 关闭资源在某些情况下有可能执行不到,所以可以放到try里面,多个对象之间用 ; 隔开
// try最后会自动关闭资源 比finally更方便一些
// 之前写的代码也可以优化成这种写法
try (Reader reader = new FileReader("D:/ATest/hello/haha.txt");
Reader reader2 = new FileReader("D:/ATest/hello/haha.txt");
Reader reader3 = new FileReader("D:/ATest/hello/haha.txt")){
while (true) {
int len = reader.read();
if (len == -1) {
break;
}
System.out.printf("%c " ,(char)len);
}
System.out.println();
System.out.println();
while (true) {
char[] arr1 = new char[20];
int len = reader2.read(arr1);
if (len == -1) {
break;
}
for (int i = 0; i < len; i++) {
System.out.printf("%c ", arr1[i]);
}
System.out.println();
}
System.out.println();
while (true) {
char[] arr2 = new char[20];
int off = 3;
int len = reader3.read(arr2, off, 9);
System.out.println(len);
if (len == -1) {
break;
}
for (int i = off; i < len; i++) {
System.out.printf("%c ", arr2[i]);
}
}
}
}
}
写
这里的写比字节流多了一些方法,可以追加写
// 写文件
// 测试字符流
// Writer
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class IODemo10 {
public static void main (String[] args) throws IOException {
// writer 会清空文件原内容写
// writer2 会保留文件内容写
try (Writer writer = new FileWriter("D:/ATest/hello/haha.txt");
Writer writer2 = new FileWriter("D:/ATest/hello/haha.txt", true)){
writer.write("writer写的");
writer.append(" 用writer追加写的");
writer2.write(" writer2写的");
writer2.append(" 用writer2追加写的");
// 写完要冲刷进去,防止留在缓冲区
writer.flush();
writer2.flush();
}
}
}
代码例子
删除文件
目标删除haha.docx
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class IODemo11 {
public static void main(String[] args) {
System.out.println("请输入根目录:");
Scanner scanner = new Scanner(System.in);
String rootName = scanner.next();
File root = new File(rootName);
if (!root.exists()) {
System.out.println("没有此目录!");
return;
}
System.out.println("请输入文件名字:");
String name = scanner.next();
// 把查到的文件放到list里
// 有可能会有相同的文件名在不同的文件夹下面,或者名字相同属性不同
List<File> files = new ArrayList<>();
descFiles(root, name, files);
for (File file: files) {
System.out.println("确定要删除" + file.getPath() + " ?");
String choice = scanner.next();
if (choice.equals("Y") || choice.equals("y")) {
file.delete();
System.out.println("删除成功!");
} else {
System.out.println("取消删除!");
}
}
}
// root:根目录 name:要删除的文件名字 files:存储要删除文件的容器
private static void descFiles(File root, String name, List<File> files) {
// 文件是树的方式存储的,用递归查文件
// 先列出root下所有的文件
File[] file = root.listFiles();
// 如果目录是空的,就返回
if (file == null) {
return;
}
// 不是空的就依次查
for (File x : file) {
// 如果是目录,就递归继续查
if (x.isDirectory()) {
descFiles(x, name, files);
} else {
// 不是目录就判断是否为要删除的文件
if (x.getName().contains(name)) {
// 是就存到files
files.add(x);
}
}
}
}
}
复制文件
import java.io.*;
import java.util.Scanner;
// 文件的复制
// 使用字节流复制
public class IODemo12 {
public static void main(String[] args) throws IOException {
// 源文件 + 源路径 --> 目标文件 + 目标路径
Scanner scanner = new Scanner(System.in);
System.out.println("请输入被复制的文件名字:");
String srcName = scanner.next();
System.out.println("请输入被复制文件的路径:");
String srcPath = scanner.next();
System.out.println("请输入复制目标路径:");
String descPath = scanner.next();
// 同一个文件不能复制到相同文件夹下(除非改名字)
File descFile = new File(descPath, srcName);
if (descFile.exists()) {
System.out.println("要复制的文件已存在!无法复制!");
return;
}
File srcFile = new File(srcPath, srcName);
if (!srcFile.exists()) {
System.out.println("被复制文件不存在!");
return;
}
// 开始复制
// 源文件读进来 写给目标文件
try(InputStream inputStream = new FileInputStream(srcFile);
OutputStream outputStream = new FileOutputStream(descFile)) {
while (true) {
int b = inputStream.read();
if (b == -1) {
System.out.println("复制成功!");
break;
}
outputStream.write(b);
}
}
}
}
有什么错误评论区指出。希望可以帮到你。