Java 中通过 java.io.File 类来对⼀个⽂件(包括⽬录)进⾏抽象的描述。
注意:有 File 对象,并不代表真实存在该⽂件。
import java.io.File;
public class FileDemo1 {
public static void main(String[] args) {
File pFile=new File("d:\\");
//构造方法1
File file=new File(pFile,"a.txt");
System.out.println("文件a路径:"+file.getPath());
//构造方法2【重点,使用较多】
File file1=new File("d:\\b.txt");
System.out.println("文件b的路径:"+file1.getPath());
//构造方法3
File file2=new File("d:\\","c.txt");
System.out.println("文件c的路径:"+file2.getPath());
}
}
getPath() VS getAbsolutePath() VS getCanonicalPath():
import java.io.File;
import java.io.IOException;
public class FileDemo2 {
public static void main(String[] args) throws IOException {
File file=new File("../a.text");
System.out.println("文件名称:"+file.getName());
System.out.println("文件目录:"+file.getPath());
System.out.println("文件绝对路径:"+file.getAbsolutePath());
System.out.println("文件的标准路径:"+file.getCanonicalPath());
}
}
● 绝对路径时,三者⼀致。
●相对路径时:
○ getPath() 是相对路径本身;
○ getAbsolutePath() 是项⽬⽬录 + 相对路径本身;
○ getCanonicalPath() 可以解析相对路径,得到正确的路径。
import java.io.File;
import java.io.IOException;
public class FileDemo3 {
public static void main(String[] args) throws IOException {
File file=new File("a.txt");
System.out.println("文件是否存在:"+file.exists());
System.out.println("是否为文件夹:"+file.isDirectory());
System.out.println("是否为文件:"+file.isFile());
System.out.println();
boolean result=file.createNewFile();//创建文件
System.out.println("文件创建:"+result);
System.out.println("文件是否存在:"+file.exists());
System.out.println("是否为文件夹:"+file.isDirectory());
System.out.println("是否为文件:"+file.isFile());
}
}
结论:如果⽂件或⽂件夹不存在,使⽤ isDirectory 和 isFile 判断都为 false。
import java.io.File;
import java.io.IOException;
public class FileDemo4 {
public static void main(String[] args) throws IOException {
//先得到一个file对象
File file = new File("a.text");//存在a.txt文件
//判断file对象是否存在
if (file.exists()) {
//如果存在则删除文件
boolean result = file.delete();
System.out.println("文件删除:" + result);
} else {
//如果不存在则创建文件
boolean result=file.createNewFile();
System.out.println("新建文件:"+result);
}
}
}
import java.io.File;
import java.io.IOException;
public class FileDemo5 {
public static void main(String[] args) throws IOException, InterruptedException {
File file=new File("a.txt");
if (!file.exists()){
//如果不存在。新建文件
System.out.println("新建文件:"+file.createNewFile());
}
//删除文件
System.out.println("开始删除文件");
file.deleteOnExit();
//file.delete();
Thread.sleep(5*1000);
}
}
结论:
1.delete()有返回值,deleteOnExit()没有返回值。
2.deleteOnExit():程序正常运⾏结束,⽂件被删除;但如果是⼈为停止或退出程序,⽂件不会被删除。
3.delete():不管是程序正常运行结束还是人为结束,文件都会被删除。
mkdir():只能创建一级文件夹
mkdirs():可以创建多级文件夹
import java.io.File;
public class FileDemo6 {
public static void main(String[] args) {
File file=new File("mytest");//不存在
System.out.println("是否为文件夹:"+file.isDirectory());
System.out.println("是否为文件:"+file.isFile());
System.out.println();
boolean result=file.mkdir();//创建文件夹
System.out.println("创建文件夹:"+result);
System.out.println("是否为文件夹:"+file.isDirectory());
System.out.println("是否为文件:"+file.isFile());
}
}
当创建多级目录时,mkdir()无法成功创建,运行结果如下:
使用**mkdirs()**可以解决这个问题:
import java.io.File;
public class FileDemo6 {
public static void main(String[] args) {
File file=new File("mytest/apps");//不存在
System.out.println("是否为文件夹:"+file.isDirectory());
System.out.println("是否为文件:"+file.isFile());
System.out.println();
boolean result=file.mkdirs();//创建文件夹
System.out.println("创建文件夹:"+result);
System.out.println("是否为文件夹:"+file.isDirectory());
System.out.println("是否为文件:"+file.isFile());
}
}
import java.io.File;
import java.io.IOException;
public class FileDemo7 {
public static void main(String[] args) throws IOException {
//将a.txt->重命名成b.txt
File file=new File("a.txt");
File tarFile=new File("b.txt");
if (!file.exists()){
//先创建文件
file.createNewFile();
}
//重命名文件
boolean result=file.renameTo(tarFile);
System.out.println("重命名结果:"+result);
}
}
执⾏两次观察结果可知:如果 renameTo 的⽂件不存在,那么可以重命名成功,反之则不成功。
InputStream 输⼊流是⽤来读取数据的。
InputStream 只是⼀个抽象类,要使⽤还需要具体的实现类。关于 InputStream 的实现类有很多,基本可以认为不同的输⼊设备都可以对应⼀个 InputStream 类,我们现在只关⼼从⽂件中读取,所以使⽤FileInputStream。
读取⽅式1: 一个字符一个字符读取
package io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class InputStreamDemo1 {
public static void main(String[] args) {
//1.创建流对象
// 这种写法异常处理太繁琐,代码看起来很臃肿
InputStream inputStream=null;
try {
inputStream=new FileInputStream("c.txt");
//2.读写操作
while (true){
int c=inputStream.read();
if (c==-1) break;//如果流返回-1,说明数据已经读取完毕
//让程序稍休眠一会儿,可以明显观察到read()方法时一个字符一个字符读取的
Thread.sleep(300);
System.out.printf("%c",c);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//3.关闭流
if (inputStream!=null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
代码优化:
package io;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStreamDemo2 {
public static void main(String[] args) {
//1.创建流对象 try-catch-resource(JDK 1.7):不用进行资源的关闭。jdk会帮助我们关闭资源
try (InputStream inputStream = new FileInputStream("c.txt")) {
//2.读写操作
while (true) {
int c = inputStream.read();
if (c == -1) break;//如果流返回-1,说明数据已经读取完毕
//让程序稍休眠一会儿,可以明显观察到read()方法时一个字符一个字符读取的
Thread.sleep(300);
System.out.printf("%c", c);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package io;
import java.io.FileInputStream;
import java.io.InputStream;
/**
* 一次性读取
*/
public class InputStreamDemo3 {
public static void main(String[] args) {
try (InputStream inputStream = new FileInputStream("c.txt")) {
byte[] bytes=new byte[1024];
while (true) {//如果数据超过了byte容量,会读取多次
int c = inputStream.read(bytes);
if (c==-1)break;
Thread.sleep(300);//即使写了休眠也没有用,因为每次最多可以读取1024个字符。
System.out.println(new String(bytes,"utf-8"));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
我们可以使⽤ Scanner 进⾏数据读取,它有⼀个构造⽅法:
package io;
import java.io.FileInputStream;
import java.util.Scanner;
public class InputStreamDemo4 {
public static void main(String[] args) {
try(FileInputStream inputStream=new FileInputStream("c.txt")){
try(Scanner scanner=new Scanner(inputStream,"utf8")){
while (scanner.hasNext()){
System.out.println(scanner.nextLine());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
OutputStream 输出流是进⾏数据写⼊的。
OutputStream 同样只是⼀个抽象类,要使⽤还需要具体的实现类。我们现在还是只关⼼写⼊⽂件中,所以使⽤ FileOutputStream。
⼀个⼀个字符写⼊:
package io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
*写入,每次写入一个字符
*/
public class OutputStreamDemo1 {
public static void main(String[] args) throws IOException {
File file=new File("mytext.txt");
if (!file.exists()){
//新建文件
System.out.println("新建文件:"+file.createNewFile());
}
//文件写入操作
try(OutputStream outputStream=new FileOutputStream(file)){
outputStream.write('G');
outputStream.write('r');
outputStream.write('e');
outputStream.write('a');
outputStream.write('t');
outputStream.flush();//不能忘记!
}
}
}
package io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class OutputStreamDemo2 {
public static void main(String[] args) throws IOException {
File file=new File("mytext.txt");
if (!file.exists()){
//新建文件
file.createNewFile();
}
//文件写入操作
try(OutputStream outputStream=new FileOutputStream(file)){
byte[] bytes=new byte[]{
'h','e','l','l','o'
};
outputStream.write(bytes);
outputStream.flush();
}
}
}
package io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class OutputStreamDemo3 {
public static void main(String[] args) throws IOException {
File file=new File("mytext.txt");
if (!file.exists()){
//新建文件
file.createNewFile();
}
//文件写入操作
try(OutputStream outputStream=new FileOutputStream(file)){
String msg="hello,word";
outputStream.write(msg.getBytes());
outputStream.flush();
}
}
}
字符串中⽂写⼊:
package io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
public class OutputStreamDemo3 {
public static void main(String[] args) throws IOException {
File file=new File("mytext.txt");
if (!file.exists()){
//新建文件
file.createNewFile();
}
//文件写入操作
try(OutputStream outputStream=new FileOutputStream(file)){
String msg="你好";
//outputStream.write(msg.getBytes("utf-8"));
outputStream.write(msg.getBytes(StandardCharsets.UTF_8));
outputStream.flush();
}
}
}
除了上述的写⼊⽅式之外,JDK 还提供了⼀个类 PrintWriter 可以很⽅便的实现数据写⼊。PrintWriter 类中提供了我们熟悉的 print/println/printf ⽅法。
package io;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
public class OutputStreamDemo4 {
public static void main(String[] args) throws IOException {
File file=new File("mytext.txt");
if (!file.exists()){
file.createNewFile();
}
try (PrintWriter printWriter=new PrintWriter(file)){
printWriter.println("这是第一行数据");
printWriter.println("这是第二行数据");
printWriter.printf("我叫:%s,今年:%d岁。","张三",18);
printWriter.flush();
}
}
}
问题:使⽤ PrintWriter 每次都会覆盖掉原来的数据,追加数据就需要使用 FileWriter类。
package io;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class OutputStreamDemo5 {
public static void main(String[] args) throws IOException {
File file=new File("mytext.txt");
if (!file.exists()){
file.createNewFile();
}
//数据追加
//第二个参数为:是否追加数据?
// 默认为false 所以一定要设置第二个参数为true!!!否则追加会无效果
try (FileWriter fileWriter=new FileWriter(file,true)){
// fileWriter.write("我是追加的数据。");
fileWriter.write("\n我是追加的数据。");//换行追加:\n
fileWriter.flush();
}
}
}
扫描指定⽬录,并找到名称中包含指定字符的所有普通⽂件(不包含⽬录),并且后续询问⽤户是否要删除该⽂件。
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Demo1 {
public static void main(String[] args) throws IOException {
Scanner scanner=new Scanner(System.in);
System.out.print("请输入要扫描的目录(绝对路径/相对路径):");
String rootDirPath=scanner.next();
File rootDir=new File(rootDirPath);
if (!rootDir.isDirectory()){
System.out.println("您输入的根目录不存在或者不是目录,退出");
return;
}
System.out.println("请输入要找出的文件的名称:");
String token=scanner.next();
//因为文件系统时树形结构的,所以我们要使用深度优先递归完成遍历
List<File> result=new ArrayList<>();
sanDir(rootDir,token,result);
System.out.println("共找到了符合条件的文件"+result.size()+"个,它们分别是");
for (File file:result){
System.out.println(file.getCanonicalFile()+"请问您是否要删除该文件?y/n");
String in=scanner.next();
if (in.toLowerCase().equals("y")){
file.delete();
}
}
}
private static void sanDir(File rootDir, String token, List<File> result) {
File[] files=rootDir.listFiles();
if (files==null||files.length==0){
return;
}
for (File file:files){
if (file.isDirectory()){
sanDir(file,token,result);
}else {
if (file.getName().contains(token)){
result.add(file.getAbsoluteFile());
}
}
}
}
}
进⾏普通⽂件的复制。
import java.io.*;
import java.util.Scanner;
/**
* 进行普通文件的复制
*/
public class Demo2 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("请输入要复制的文件(绝对路径/相对路径):");
String sourcePath=scanner.next();
File sourceFile=new File(sourcePath);
if (!sourceFile.exists()){
System.out.println("文件不存在,请确认路径是否正确");
return;
}
if (!sourceFile.isFile()){
System.out.println("文件不是普通文件,请确认路径是否正确");
return;
}
System.out.println("请输入要复制到的目标路径(绝对路径/相对路径):");
String destPath=scanner.next();
File destFile=new File(destPath);
if (destFile.exists()){
if (destFile.isDirectory()){
System.out.println("⽬标路径已经存在,并且是⼀个⽬录,请确认路径是否正确");
return;
}
if (destFile.isFile()){
System.out.println("目录路径已经存在,是否进行覆盖?y/n");
String ans=scanner.next();
if (!ans.toLowerCase().equals("y")){
System.out.println("停止复制");
return;
}
}
}
try(InputStream is=new FileInputStream(sourceFile)) {
try(OutputStream os=new FileOutputStream(destFile)){
byte[] buf=new byte[1024];
int len;
while (true){
len=is.read(buf);
if (len==-1){
break;
}
os.write(buf,0,len);
}
os.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 Demo3 {
public static void main(String[] args) throws IOException {
Scanner scanner=new Scanner(System.in);
System.out.println("请输入要扫描的根目录(绝对路径/相对路径):");
String rootDirPath=scanner.next();
File rootDir=new File(rootDirPath);
if (!rootDir.isDirectory()){
System.out.println("您输入的根目录不存在火灾不是目录,退出");
return;
}
System.out.println("请输入要找出的文件名中的字符:");
String token=scanner.next();
List<File> result=new ArrayList<>();
// 因为⽂件系统是树形结构,所以我们使⽤深度优先遍历(递归)完成遍历
scanDirWithContent(rootDir,token,result);
System.out.println("共找到了符合条件的文件"+result.size()+"个,它们分别是");
for (File file:result){
System.out.println(file.getCanonicalFile());
}
}
private static void scanDirWithContent(File rootDir, String token, List<File> result) {
File[] files=rootDir.listFiles();
if (files==null||files.length==0){
return;
}
for(File file:files){
if (file.isDirectory()){
scanDirWithContent(file,token,result);
}else {
if (isContentContains(file,token)){
result.add(file.getAbsoluteFile());
}
}
}
}
private static boolean isContentContains(File file, String token) {
StringBuilder sb=new StringBuilder();
try(InputStream is=new FileInputStream(file)){
try(Scanner scanner=new Scanner(is,"UTF-8")){
while (scanner.hasNextLine()){
sb.append(scanner.nextLine());
sb.append("\r\n");
}
}
} catch (IOException e) {
e.printStackTrace();
}
return sb.indexOf(token)!=-1;
}
}