一、操作文件的属性
Java标准库提供可以操作文件的类:File
1.File类里面的方法
import java.io.File;
import java.io.IOException;
public class Test03 {
public static void main(String[] args) throws IOException {
File file=new File("./test01");
System.out.println("获取文件的名字"+file.getName());
System.out.println("获取文件路径"+file.getPath());
System.out.println("获取文件的绝对路径"+file.getAbsoluteFile());//当前目录+new File()括号里面的内容
System.out.println("获取文件的绝对路径"+file.getCanonicalFile());
System.out.println("文件是否存在"+file.exists());
System.out.println("文件是否是目录"+file.isDirectory());
System.out.println("是否是文件"+file.isFile());
}
}
2.删除文件file.delete():删除成功:true;删除失败:false
import java.io.File;
public class Test06 {
public static void main(String[] args) throws InterruptedException {
File file=new File("F:\\Test_2_4\\Test01\\test01.doc");
System.out.println("文件是否存在"+file.exists());
Thread.sleep(1000);
//删除文件
System.out.println(file.delete());
}
}
删除文件:deleteOnExit():当整个程序执行完了之后,才会关闭文件
import java.io.File;
import java.io.IOException;
public class Test08 {
public static void main(String[] args) throws IOException, InterruptedException {
File file=new File("F:\\Test_2_4\\Test01\\demo001.doc");
System.out.println("1.是否存在文件"+file.exists());
file.createNewFile();
System.out.println("2.是否存在文件"+file.exists());
Thread.sleep(3000);
//程序先执行完,然后文件删除
file.deleteOnExit();
System.out.println("3.是否存在文件"+file.exists());//先执行这个代码,等到整个程序执行完了之后,才删除文件
System.out.println("程序执行结束");
}
}
3.新增文件createNewFile()
import java.io.File;
import java.io.IOException;
public class Test07 {
public static void main(String[] args) throws IOException {
File file=new File("F:\\Test_2_4\\Test01\\test01.doc");
System.out.println("文件是否存在"+file.exists());
System.out.println("删除文件是否成功"+file.delete());
//看当前路径下这个文件是否存在,如果不存在就创建,如果存在该文件,执行这个代码,不会产生新的文件
file.createNewFile();
System.out.println(file.getAbsolutePath());
}
}
4.获取一个路径下的所有文件
思路:递归调用
首先,判断是文件还是文件夹,文件直接加到list当中,如果是文件夹,就获取该目录下所有的文件名,递归调用获取文件的方法。
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class Test05 {
public static List<File> files=new ArrayList<>();
public static List<File> getFile(String path){
File f=new File(path);
if(f.isFile()){
files.add(f);
}else if(f.isDirectory()){
String[] result=f.list();
for(String s:result){
getFile(path+"/"+s);
}
}
return files;
}
public static void main(String[] args) {
String path="F:\\Test_2_4";
List<File> files=getFile(path);
for (File file:files){
System.out.println(file.getAbsolutePath());
}
}
}
5.创建目录mkdir():只支持创建一层目录
import java.io.File;
import java.io.IOException;
public class Test09 {
public static void main(String[] args) throws IOException {
File file=new File("F:\\Test_2_4\\Test01\\Test002\\a");
System.out.println("1.是否存在目录"+file.exists());
file.mkdir();
System.out.println("2.是否存在目录"+file.exists());
}
}
创建多级目录,mkdir()无法完成,需要利用mkdirs()方法
import java.io.File;
import java.io.IOException;
public class Test09 {
public static void main(String[] args) throws IOException {
File file=new File("F:\\Test_2_4\\Test01\\Test002\\a\\b\\c");
System.out.println("1.是否存在目录"+file.exists());
file.mkdirs();
System.out.println("2.是否存在目录"+file.exists());
}
}
6.文件重命名、文件切换路径:renameTo()
文件剪切:只需要修改文件路径(修改文件的属性),开销小;
文件复制粘贴:需要读取文件,拷贝内容,粘贴内容,整个开销比较大。
//1.文件改名
import java.io.File;
public class Test10 {
public static void main(String[] args) throws InterruptedException {
File file=new File("F:\\Test_2_4\\Test01\\Test002\\b");
File file2=new File("F:\\Test_2_4\\Test01\\Test002\\a");
System.out.println("1.文件名字"+file.getAbsolutePath());
file.renameTo(file2);
}
}
修改之前:
修改之后:
//2.切换目录
import java.io.File;
public class Test11 {
public static void main(String[] args) {
File file=new File("F:\\Test_2_4\\Test02\\test01\\temp.doc");
File file2=new File("F:\\Test_2_4\\Test02\\temp.doc");
//切换目录
file.renameTo(file2);
}
}
切换前:
切换后
二、文件的读写
读、写文件–流
1.字节流(以字节流的形式去读写文件)
文件读取:Java标准库提供了InputStream(抽象类),实现类:FileInputStream。
往文件中写:OutputStream,实现类:FileOutputStream。
2.抽象类abstract修饰的类
主要特点是:
1.不能被实例化;
2.抽象方法必须放在抽象类当中;
3.抽象类既可以包含抽象方法也可以包含非抽象方法;
4.抽象类中的抽象方法没有具体的方法体。
如何使用抽象方法?
写一个子类继承抽象类,重写抽象方法。
如果需要设计一个类不能被实例化,就需要将这个类用abstract修饰。
3.接口
主要特点:
1.接口中方法的默认修饰符是:public abstract
2.接口中变量的默认修饰符是:public static int
3.接口中方法是没有方法体的。
4.接口、抽象类
1.一个普通成员(非静态成员)能否在抽象类中存在?能否在接口中存在?
一个普通普通的成员可以在抽象类中存在,
也不能在接口中存在,因为接口中的成员默认修饰符是public static final。
2.一个普通的方法(非抽象方法)能否在抽象类中存在?能否在接口中存在?
一个普通的方法可以在抽象类中存在,不可以在接口中存在,接口中的方法默认修饰符是public abstract。
3.一个抽象方法,能否在抽象类中存在?能否在接口中存在?
抽象方法必须在抽象类中存在,可以在接口中存在,接口中方法的默认修饰符是:public abstract。
4.一个类,能否继承多个抽象类?
不可以,一个类只能有一个父类,不允许多继承。
5.一个类,能否实现多个接口?
可以,一个类可以实现多个接口。
5.读文件:read()–>返回值类型:int
a. read():无参数,代表按照单个字节来读取文件,返回值是-1,代表读取完毕
import java.io.*;
//读取文件中的内容
public class Test02 {
public static void main(String[] args) {
InputStream inputStream=null;
try {
inputStream=new FileInputStream("F:\\Test_2_4\\demo03.txt");
while(true){
int ret=inputStream.read();
if(ret==-1){
System.out.println("读取完毕");
break;
}
System.out.printf("%c",ret);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
代码结果图:
b. read(byte[] b):带有一个参数,以字节数组读取文件
下面举例:一次读取1024个字节,与一次读取一个字节相比:
减少了读取文件的次数,加大了执行效率,读文件的操作是十分缓慢的。
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class Test04 {
public static void main(String[] args) {
try(InputStream inputStream=new FileInputStream("F:\\Test_2_4\\demo03.txt")){
byte[] bytes=new byte[1024];
while (true){
//每次读取1024个字节
int ret=inputStream.read(bytes);
if(ret==-1){
System.out.println("读取结束");
break;
}
for (int i=0;i<bytes.length;i++){
System.out.printf("%c",bytes[i]);
}
}
}catch(IOException e){
e.printStackTrace();
}
}
}
结果展示:
c.如果文件当中有中文,该如何去读取呢?
中文和英文编码方式是不一样的,
中文采取的编码方式是uft-8或者是gbk
英文采取的编码方式是ascii
上面代码中打印,‘%c’,采用的编码方式是ascii,如果文件中存在中文,在打印的时候,会出现乱码的情况。
如何解决这种问题呢?
引入了Java标准库中提出的内置字符集的方式Scanner
Scanner:不仅可以从控制台读取标准输入值还可以从文件中读取文件内容
//第一版本
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;
public class Test05 {
public static void main(String[] args) {
try(InputStream inputStream=new FileInputStream("F:\\Test_2_4\\demo03.txt")){
Scanner scanner=new Scanner(inputStream,"UTF-8");
while(scanner.hasNext()){
String s=scanner.next();
System.out.println(s);
}
}catch(IOException e){
e.printStackTrace();
}
}
}
//第二版本:Scanner本身也有close操作
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;
public class Test05 {
public static void main(String[] args) {
try(InputStream inputStream=new FileInputStream("F:\\Test_2_4\\demo03.txt")){
//Scanner里面也有close关闭,在这里,实际上关闭的是inputStream
try(Scanner scanner=new Scanner(inputStream,"UTF-8")){
while(scanner.hasNext()){
String s=scanner.next();
System.out.println(s);
}
}
}catch(IOException e){
e.printStackTrace();
}
}
}
结果:
上面的代码针对Scanner来说,进行了关闭操作。但是在Scanner in=new Scanner(System.in)代码当中,对Scanner没有进行关闭,这是为什么呢?
System.in:标准输入,一般不关闭,在创建进程的时候,系统就会自动打开标准输入、标准输出、标准错误这三个文件,当销毁进程的时候,这三个文件也就被关闭了,一般不会手动关闭。
6.资源泄漏是什么?
操作系统中的资源都是有限的。资源会指内存,文件描述符表…
文件描述符表是什么?
在用户态每创建一个进程或者是一个线程的时候,对应的,在内核态中就会创建一个PCB,PCB的属性当中,有一个文件描述符表。
进程中每打开一个文件,就会产生一个文件描述符,就会把这个文件描述符添加到文件描述符表当中。当不使用文件的时候,未关闭文件,当文件越来越多,以致将整个文件描述符表都占满了之后,再打开新的文件,就会产生打开文件失败的情况。
7.往文件中写数据-OutputStream
a.刷新flush
刷新flush一般会用到什么样的场景下?
缓冲区实际上是一段内存空间,OutputStream自带一块缓冲区,是介于内存和磁盘之间,写数据一般会写在缓冲区当中,当缓冲区满了之后/手动调用刷新flush之后,会将缓冲区中的内容写到磁盘当中。
b.往文件中写数据
一旦按照OutputStream的方式打开文件,就会清空文件中的内容。
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class Test06 {
public static void main(String[] args) {
//按照OutputStream的方式打开一个文件,一般会将文件中的内容删除掉
try(OutputStream outputStream=new FileOutputStream("F:\\Test_2_4\\demo03.txt")){
//1.写一个字符
outputStream.write('a');
//2.写一个字符数组
byte[] bytes=new byte[]{
(byte)'a',(byte)'b',(byte)'c',(byte)'d'
};
outputStream.write(bytes);
//3.写一个字符串
String s="明天,你好";
outputStream.write(s.getBytes());
}catch(IOException e){
e.printStackTrace();
}
}
}
结果:
c.封装了一个类,主要完成往文件中填写数据PrintWrite
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
public class Test07 {
public static void main(String[] args) {
try(OutputStream outputStream=new FileOutputStream("F:\\Test_2_4\\demo03.txt")){
try(PrintWriter printWriter=new PrintWriter(outputStream)){
printWriter.println("明天你好,hello");
}
}catch (IOException e){
e.printStackTrace();
}
}
}
三、拓展
1.查找文件,并且指定是否要删除文件
指定一个目录,扫描这个目录,找到文件名中包含了指定字符的文件,并提示用户是否要删除这个文件,根据用户的决定是否进行删除操作。
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Test10 {
public static List<File> findFile(String path,String name){
List<File> fileList=new ArrayList<>();
File file=new File(path);
File[] files=file.listFiles();
for (File f:files){
if(f.isFile()){
fileList.add(f);
}else if(f.isDirectory()){
try {
String tempPath=f.getCanonicalPath();
findFile(tempPath,name);
} catch (IOException e) {
e.printStackTrace();
}
}
}
return fileList;
}
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
System.out.println("请输入指定目录");
String path=in.next();
File file=new File(path);
if(!file.isDirectory()){
System.out.println("输入文件路径错误,退出");
return;
}
System.out.println("请输入要删除文件的文件名:");
String name=in.next();
List<File> list=findFile(path,name);
for (File f:list){
if (f.getName().contains(name)){
System.out.println("是否要删除该文件:yes/no");
String judge=in.next();
if(judge.equals("yes")){
f.delete();
System.out.println("删除成功,退出");
return;
}else{
System.out.println("不删除文件,退出");
return;
}
}
}
System.out.println("文件没有被找到");
}
}
结果展示:
2.复制一个文件
启动程序之后,让用户输入一个文件的路径(绝对路径),要求这个文件是一个普通文件(不是目录),再指定一个目标路径,通过程序,将这个文件进行复制目标路径下。
import java.io.*;
import java.util.Scanner;
public class Test11 {
public static void main(String[] args) throws IOException {
Scanner in=new Scanner(System.in);
System.out.println("请输入一个文件的绝对路径");
String path=in.next();
File file=new File(path);
if(!file.isFile()){
System.out.println("输入内容有误,退出");
return;
}
System.out.println("请输入复制的目的路径");
String aimPath=in.next();
File aimFile=new File(aimPath);
if(aimFile.exists()){
System.out.println("文件已经存在,退出");
return;
}
if(!aimFile.getParentFile().exists()){
System.out.println("文件目录不存在,创建文件目录");
String tempPath=aimFile.getParentFile().getCanonicalPath();
File tempFile=new File(tempPath);
tempFile.mkdirs();
}
try(InputStream inputStream=new FileInputStream(path);
OutputStream outputStream=new FileOutputStream(aimPath)){
while(true){
byte[] bytes=new byte[1024];
int ret=inputStream.read(bytes);
if(ret==-1){
break;
}
outputStream.write(bytes,0,ret);
}
outputStream.flush();
}catch(IOException e){
e.printStackTrace();
}
System.out.println("复制完成");
}
}
结果:
通过这些文件操作,在指定目录中按照文件内容查找,看看是否包含匹配的结果
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Test12 {
public static void main(String[] args) throws IOException {
Scanner in=new Scanner(System.in);
System.out.println("请输入要查找的绝对路径");
String srcPath=in.next();
File srcFile=new File(srcPath);
if(!srcFile.isDirectory()){
System.out.println("输入有误,退出");
return;
}
System.out.println("请输入要查找的内容");
String srcFind=in.next();
List<File> files=new ArrayList<>();
findFile(srcPath,srcFind,files);
for (File f:files){
System.out.println(f.getCanonicalFile());
}
if(files.size()==0){
System.out.println("没有找到要查找的内容");
}
}
public static void findFile(String srcPath,String srcFind,List<File> files) throws IOException {
File srcFile=new File(srcPath);
//获取该目录下的所有文件、目录
File[] tempFile=srcFile.listFiles();
for (File f:tempFile){
if(f.isDirectory()){
//如果是目录,就递归调用
findFile(f.getCanonicalPath(),srcFind,files);
}else if(f.isFile()){
if(containsContent(f.getCanonicalPath(),srcFind)){
files.add(f);
}
}
}
}
public static boolean containsContent(String path,String srcFind){
StringBuilder stringBuilder=new StringBuilder();
try(InputStream inputStream=new FileInputStream(path)) {
Scanner scanner=new Scanner(inputStream,"UTF-8");
while (scanner.hasNextLine()){
String temp=scanner.nextLine();
stringBuilder.append(temp);
}
} catch (IOException e) {
e.printStackTrace();
}
return stringBuilder.indexOf(srcFind)!=-1;
}
}
结果: