目录
File的常见方法
普通文件的创建
普通文件的删除
deleteOnExit
目录的创建
mkdir
mkdirs
文件的重命名和剪切
剪切
重命名
InputStream
read()
OutputStream
write()
Reader
Writer
write(String str)
代码练习
扫描指定⽬录,并找到名称中包含指定字符的所有普通⽂件(不包含⽬录),并且后续询问⽤⼾是否 要删除该⽂件
进⾏普通⽂件的复制
扫描指定⽬录,并找到名称或者内容中包含指定字符的所有普通⽂件(不包含⽬录)
File是Java中的一个重要类,位于java.io包中,可以用来创建、删除、查询文件或目录等
什么是文件(File)?
文件可以是文本、图像、视频、音频、程序代码等多种类型的数据
什么是目录(Directory)?
通俗点来说,目录就是文件夹,用于将多个文件存放在一起,便于管理
什么是绝对路径,什么是相对路径,什么是工作路径?
绝对路径就是从根目录开始的,绝对路径不受当前工作路径的影响,而相对路径就是从当前目录开始,System.getProperty("user.dir") 这种方式来获取当前的工作路径
public static void main(String[] args) throws IOException {File file = new File("test1.txt");System.out.println(file.getName());//文件或目录最后一个路径元素System.out.println(file.getPath());//返回文件的路径System.out.println(file.getAbsoluteFile());//返回文件的绝对路径System.out.println(file.getCanonicalFile());//返回文件规范的绝对路径}
运行结果:
File的常见方法
返回值 | 方法名 | 说明 |
String | getParent() | 返回 File 对象的⽗⽬录⽂件路径 |
String | getName() | 返回文件或目录的最后一个名称 |
String | getPath() | 返回 File 对象的⽂件路径 |
String | getAbsolutePath() | 返回 File 对象的绝对路径 |
String | getCanonicalPath() | 返回文件的规范绝对路径 |
boolean | exists() | 判断 File 对象描述的⽂件是否存在 |
boolean | isDirectory() | 判断 File 对象代表的⽂件是否是⼀个⽬录 |
boolean | isFile() | 判断 File 对象代表的⽂件是否是⼀个普通⽂件 |
boolean | createNewFile() | 根据 File 对象,⾃动创建⼀个空⽂件,成功创建后返回 true |
boolean | delete() | 根据 File 对象,删除该⽂件。成功 删除后返回 true |
void | deleteOnExit() | 根据 File 对象,标注⽂件将被删除, 删除动作会到 JVM 运⾏结束时才会进⾏ |
String[] | list() | 返回目录中的每个文件和目录的名称(不包括路径) |
File[] | listFiles() | 返回目录中所有文件和子目录的File 对象(包括路径) |
boolean | mkdir() | 创建单个目录,父目录必须存在 |
boolean | mkdirs() | 创建多级目录,父目录不存在则会自动创建父目录 |
boolean | renameTo(File dest) | 进⾏⽂件改名,也可以视为我们平时的剪切、粘贴操作 |
boolean | canRead() | 判断⽤⼾是否对⽂件有可读权限 |
boolean | canWrite() | 判断⽤⼾是否对⽂件有可写权限 |
普通文件的创建
public static void main(String[] args) throws IOException {File file = new File("D:\\java");System.out.println(file.exists());//trueSystem.out.println(file.isDirectory());//true,因为‘java’为目录System.out.println(file.isFile());//falseSystem.out.println(file.createNewFile());//false,因为‘java’是个文件夹如果//再次创建的话会返回false,如果改成其他名字就可以创建成功}
普通文件的删除
public static void main(String[] args) throws IOException {File file = new File("D:\\java\\test1.txt");System.out.println(file.exists());//返回false,因为test1.txt并没有在’java‘这个路径上System.out.println(file.createNewFile());//返回true,并成功创建出test1.txt这个文本文件System.out.println(file.exists());//返回true,因为成功创建出了test1.txt,所以可以找到System.out.println(file.delete());//返回true,因为存在所以可以删除,如果不存在则删除失败返回falseSystem.out.println(file.exists());//返回false,因为成功删除,所以在当前路径下找不到test1.txt}
deleteOnExit
我们可以将这个理解成延迟删除,意思是只有当程序运行结束的时候才会删除
public static void main(String[] args) {File file = new File("D:\\java\\test.txt");file.deleteOnExit();Scanner scanner = new Scanner(System.in);System.out.println("请随便输入");scanner.next();//输入,用来观察是否被删除System.out.println("删除成功");}
通过下面这张图可以观察到当程序还未结束的时候,这个文件是没有被删除的,但是当我输入完并按下回车之后,这个文件就会立刻被删掉
目录的创建
mkdir
public static void main(String[] args) {File file = new File("D:\\java\\newFile1");System.out.println(file.isDirectory());//用来判断是否为目录,如果是返回true,如果不是返回falseSystem.out.println(file.mkdir());//创建成功,因为‘java’这个目录存在//如果‘java’这个目录不存在则创建失败,那么就使用mkdirs}
mkdirs
mkdirs与mkdir不同的是,对于mkdirs来说如果父目录,也就是中间目录不存在的话则会自动创建父目录,而后者不会
public static void main(String[] args) {File file = new File("D:\\java\\newFile2\\newFile3");System.out.println(file.mkdirs());//在‘java’这个目录下创建一个newFile2目录//并在newFile2这个目录下创建newFile3,因为newFile2这个目录不存在,但是我们使用的是//mkdirs所以会自动帮我们创建好newFile2这个目录}
文件的重命名和剪切
剪切
public static void main(String[] args) {File src = new File("D:\\java\\test1.txt");File dest = new File("D:\\java\\File1\\test2.txt");System.out.println(src.exists());System.out.println(dest.exists());System.out.println(src.renameTo(dest));}
没执行前
java文件中保存着test1.txt 和 test2.txt 这两个文本文件,并且File1 目录里面为空
程序执行后
将D:\java\test1.txt
移动到 D:\java\File1\
目录并重命名为 test2.txt
重命名
public static void main(String[] args) {File src = new File("D:\\java\\test1.txt");File dest = new File("D:\\java\\test3.txt");System.out.println(src.exists());System.out.println(dest.exists());//要求test3不存在System.out.println(src.renameTo(dest));}
运行结果
只有当目标文件不存在的时候才能完成重命名操作,所以上述代码成功将 test1.txt 重命名为 test3.txt
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() | 关闭字节流 |
InputStream 只是⼀个抽象类,要使⽤还需要具体的实现类。
read()
代码1
public static void main(String[] args) throws IOException {InputStream inputStream = new FileInputStream("D:\\java\\test.txt");while(true){int b = inputStream.read();if(b == -1){break;}System.out.printf("%c",b);}inputStream.close();}
代码2
public static void main(String[] args) throws IOException {InputStream inputStream = new FileInputStream("D:\\java\\test.txt");while(true){byte[] buffer = new byte[1024];int len = inputStream.read(buffer);if(len == -1) break;for(int i = 0;i<len;i++){System.out.printf("%c",buffer[i]);}}}
代码2相对于代码1来说减少了大量的 IO 操作,因为 read() 方法是一次读一个字节,而代码2就是利用这一点将读取到的数据放到 buffer 里面,直到读满1024个字节或者内容读取完毕才会执行打印,这样就减少了大量的 IO 操作
运行结果就是看你的 test.txt 里面的内容是什么,但是不推荐内容包含中文,如果需要使用
FileInputStream 来查看有包含中文内容的请继续往下看
使用 FileInputStream 来读取中文
public static void main(String[] args) throws IOException {InputStream inputStream = new FileInputStream("D:\\java\\test.txt");byte[] buffer = new byte[1024];while(true){int len = inputStream.read(buffer);if(len == -1) break;for(int i = 0;i<len;i+=3){String s = new String(buffer,i,3,"UTF-8");System.out.printf("%s",s);}}inputStream.close();}
但是这样写就会有一个弊端,就是文本中必须全部都是中文,因为对于UTF8来说,每个汉字都会被分割成3个字节
OutputStream
返回值 | 方法名 | 说明 |
void | write(int b) | 写⼊要给字节的数据,一次只能写入一个字节 |
void | write(byte[] b) | 将 b 这个字符数组中的数据全部写 ⼊ os 中 一次可以写入多个字节 |
int | write(byte[] b, int off, int len) | 读取 b 这个字符数组从 [off,off+len) 的长度 |
void | close() | 关闭字节流 |
void | flush() | 我们知道 I/O 的速度是很慢 的,所以,⼤多的 OutputStream 为了减少设备操作的次数,在写数 据的时候都会将数据先暂时写⼊内 存的⼀个指定区域⾥,直到该区域 满了或者其他指定条件时才真正将 数据写⼊设备中,这个区域⼀般称 为缓冲区。但造成⼀个结果,就是 我们写的数据,很可能会遗留⼀部 分在缓冲区中。需要在最后或者合 适的位置,调⽤ flush(刷新)操 作,将数据刷到设备中。 |
write()
在代码中,如果我们使用try-with-resources
语句,则不用手动进行字符/字节流的关闭,因为如果在try代码块结束的时候就会自动调用 close ,而不需要手动进行,用来放在忘记关闭而导致的内存泄漏问题
public static void main(String[] args) {try(OutputStream os = new FileOutputStream("D:\\test.txt")){os.write('H');os.write('E');os.write('L');os.write('L');os.write('O');} catch (IOException e) {throw new RuntimeException(e);}}
但是使用上述代码我们可以看到,如果我们再进行一次写操作,之前的内容就会消失不见,这是因为只要我们使用OutputStream 打开文件,里面的内容就会消失,如何解决这个问题也很简单,因为OutputStream 默认是会清空之前的内容的,但是我们还有一个追加操作,就是在路径后面写一个“ true” 参数
OutputStream os = new FileOutputStream("D:\\java\\test.txt",true)
我们也可以用 write(byte[] b)方法进行写入,方式如下
public static void main(String[] args) {try(OutputStream os = new FileOutputStream("D:\\java\\test.txt",true)){byte[] b = new byte[]{'a','b','c','d'};os.write(b);} catch (IOException e){e.printStackTrace();}}
但是当我们使用InputStream 和 OutputStream 的时候读取和写入中文就比较麻烦,所以我们可以使用更简单的方法来进行中文的输入和输出,请看下文
Reader
public static void main(String[] args) {try(Reader reader = new FileReader("D:\\java\\test.txt")){while(true){int n = reader.read();if(n == -1){return;}char ch = (char)n;System.out.print(ch+" ");}} catch (IOException e){e.printStackTrace();}}
对于这段代码来说,不管你的内容是中文还是英文还是中英混杂都可以正确的读取出来
输出结果:
看到这里可能就会有一个疑问?明明 java 中的 char 类型表示的是 2 个字节,但是 java 中的汉字是使用 utf8 来表示的,一个汉字 3 个字节,为什么可以使用 char 来表示 3个字节的汉字呢?其实
java 的 char 在表示汉字的时候并不是用 utf8 而是使用 unicode 的编码方式,在 unicode 中一个汉字就表示 2 个字节
在这里我也推荐一个很好用的查看字符编码的网站
查看字符编码(UTF-8)http://www.mytju.com/classCode/tools/encode_utf8.asp
Writer
write(String str)
这个方法可以直接写入字符串,非常方便,如果要进行追加操作也一样在后面加个true就可以
public static void main(String[] args) {try(Writer writer = new FileWriter("D:\\java\\test.txt",true)){writer.write("你好中国");} catch (IOException e){e.printStackTrace();}}
其他方法其实和前面介绍的都差不多,这里就不再重复了
代码练习
扫描指定⽬录,并找到名称中包含指定字符的所有普通⽂件(不包含⽬录),并且后续询问⽤⼾是否 要删除该⽂件
package FileTest;import java.io.File;
import java.util.Scanner;public class demo15 {private static void scan(File currentFile,String key){if(!currentFile.isDirectory()){return;}File[] files = currentFile.listFiles();if(files.length == 0 || files == null){return;}for(File f : files){if(f.isFile()){FileDelete(f,key);} else {scan(f,key);}}}private static void FileDelete(File f,String key){if(!f.getName().contains(key)){//文件名中不包含指定的关键字return;}Scanner scanner = new Scanner(System.in);System.out.println(f.getAbsoluteFile()+"是否要删除Y/y");String choice = scanner.next();if(choice.equals("y") || choice.equals("Y")){f.delete();}}public static void main(String[] args) {System.out.println("请输入要搜索的路径");Scanner scanner = new Scanner(System.in);String rootPath = scanner.next();File rootFile = new File(rootPath);if(!rootFile.isDirectory()){System.out.println("输入的路径不存在");return;}//走到此处就说明路径存在System.out.println("请输入要删除的文件名字的关键字");String key = scanner.next();//利用递归进行查找scan(rootFile,key);}
}
进⾏普通⽂件的复制
如果文件在目录中不存在,就会自动创建,但是如果连目录都不存在那就不行了
package FileTest;import java.io.*;
import java.util.Scanner;public class demo17 {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入源文件的路径");String srcPath = scanner.next();File srcFile = new File(srcPath);if(!srcFile.isFile()){System.out.println("源文件路径有误");return;}System.out.println("请输入目标文件的路径");String destPath = scanner.next();File destFile = new File(destPath);//注意: 这里目标文件可以不存在但是父目录必须存在if(!destFile.getParentFile().isDirectory()){System.out.println("目标文件路径有误");return;}//执行复制的过程try(InputStream inputStream = new FileInputStream(srcFile);OutputStream outputStream = new FileOutputStream(destFile)){while(true){byte[] buffer = new byte[1024];int n = inputStream.read(buffer);//返回读到的字节数量if(n == -1){return;}outputStream.write(buffer,0,n);//读取0~n个,因为buffer可能装不满}} catch (IOException e) {e.printStackTrace();}}
}
代码执行前:
代码执行后:
执行过程:
D:\java\test.txt 的意思就是将 test.txt 复制到D:\java\File1 这个路径里面并重命名为 newtest.txt
这里的File1这个父目录必须存在,这段代码不仅可以复制文件还可以复制图片等
扫描指定⽬录,并找到名称或者内容中包含指定字符的所有普通⽂件(不包含⽬录)
package FileTest;import java.io.*;
import java.util.Scanner;public class demo18 {public static void main(String[] args) {System.out.println("请输入要搜索的路径");Scanner scanner = new Scanner(System.in);String rootPath = scanner.next();File rootFile = new File(rootPath);if(!rootFile.isDirectory()){System.out.println("路径不存在");return;}System.out.println("请输入要找的关键字");String key = scanner.next();scan(rootFile,key);}private static void scan(File rootFile, String key) {if(!rootFile.isDirectory()){return;}File[] files = rootFile.listFiles();if(files.length == 0 || files == null){return;}for(File f : files){if(f.isFile()){search(f,key);} else {scan(f,key);}}}private static void search(File f, String key) {StringBuilder sb = new StringBuilder();try(Reader reader = new FileReader(f)){char[] buffer = new char[1024];while(true){int n = reader.read(buffer);if(n == -1){break;}String s = new String(buffer,0,n);//将每个字符拼接成字符串sb.append(s);//将读到的字符串拼接到一起最后判断}} catch (IOException e){e.printStackTrace();}if(sb.indexOf(key) == -1){//没有找到return;}System.out.println("找到匹配的文件: "+f.getAbsolutePath());}}
上述代码只要文件中包含了关键字的都能被找的,但是这个并不能适用太复杂的目录或者文件太大的情况