Java文件IO
Posted 爱敲代码的三毛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java文件IO相关的知识,希望对你有一定的参考价值。
文章目录
Java中的文件操作
在Java中,一般谈到文件,都是指一个存在磁盘上的文件(狭义的文件),抛开Java,站在系统的角度来看,操作系统在管理很多软件资源和硬件设备的时候,都是把这些东西抽象成了一个一个的文件了,这也是系统中典型的"一切皆文件"的思想。
狭义的文件,可以分为两类
- 普通文件
- 目录文件(文件夹)
在Java标准库java.io下提供了一个File类来对文件(包括目录)进行了抽象描述,注意:有File对象并不表示File对象的文件一定存在。
File
常用构造方法
构造方法 | 说明 |
---|---|
File(File parent,String child) | 根据父目录 + 孩子文件路径,创建一个新的 File 实例 |
File(String pathname) | 根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径 |
File(String parent,String child) | 根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用路径表示 |
绝对路径:可以简单理解为带有盘符的
相对路径:基于当前位置的路径一般以 . 或 … 开头,.\\表示当前路径,…\\表示上一级路径
方法
返回值类型 | 方法名 | 说明 |
---|---|---|
Stirng | getParent() | 返回 File 对象的父目录文件路径 |
String | getName() | 返回 FIle 对象的纯文件名称 |
String | getPath | 返回 File 对象的文件路径 |
String | getAbsolutePath() | 返回 File 对象的绝对路径 |
String | getCanonicalPath() | 返回 File 对象的修饰过的绝对路径 |
boolean | exists() | 判断 File 对象描述的文件是否真实存在 |
boolean | isDirectory() | 判断 File 对象代表的文件是否是一个目录 |
boolean | isFile() | 判断 File 对象代表的文件是否是一个普通文件 |
boolean | createNewFile() | 根据 File 对象,自动创建一个空文件。成功创建后返回 true |
boolean | delete() | 根据 File 对象,删除该文件。成功删除后返回 true |
boolean | deleteOnExit() | 根据 File 对象,标注文件将被删除,删除动作会到JVM 运行结束时才会进行 |
String[] | list | 返回 File 对象代表的目录下的所有文件名 |
File[] | listFiles() | 返回 File 对象代表的目录下的所有文件,以 File 对象表示 |
boolean | mkdir() | 创建 File 对象代表的目录 |
boolean | mkdirs() | 创建 File 对象代表的目录,如果必要,会创建中间目录 |
boolean | renameTo(File dest) | 进行文件改名,也可以视为我们平时的剪切、粘贴操作 |
boolean | canRead() | 判断用户是否对文件有可读权限 |
boolean | anWrite() | 判断用户是否对文件有可写权限 |
所谓的文件移动(剪切粘贴),对于操作系统来说,其实是一个非常高效的操作。每个文件都有个属性,这个属性里就包括了文件的路径,移动操作其实只是修改了文件的路径属性而已。
所谓的文件复制(复制粘贴),对于操作系统来说,很可能是一个非常低效的操作。就需要把文件的内容都读读出来,然后再拷贝一份,写入磁盘中。如果文件比较大,复制粘贴的开销就比较大了
经典面试题
给你一个list方法,如何遍历一个目录中所有的文件(包含子目录中的文件)
public class TestDemo
private static List<String> result = new ArrayList<>();
public static void printAllFile(String path)
File file = new File(path);
//判读这个路径是否真实存在
if (file.exists())
File[] files = file.listFiles();
for (File f : files)
//如果是普通文件
if (f.isFile())
result.add(f.getName());
else if (f.isDirectory())
//如果是目录文件
printAllFile(f.getPath());
else
//其它文件..(管道)
public static void main(String[] args)
printAllFile("./");
for (String s : result)
System.out.println(s);
文件内容的读写——数据流
在Java标准库中,读写文件相关的类,有很多。
InputStream/FileInputStream
文件读取操作,按照字节为单位进行读文件
OutputStream/FileOutputStream
文件写入操作,按照字节为单位进行写文件
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() | 关闭字节流 |
注意:使用流对象,读写完文件之后,一定要及时关闭,如果没有关闭,就可能造成资源泄露
FileInputStream
构造方法 | 说明 |
---|---|
FileInputStream(File file) | 利用 File 构造文件输入流 |
FileInputStream(String name) | 利用文件路径构造文件输入流 |
public class Main
public static void main(String[] args) throws IOException
//这种写法更好
try (InputStream inputStream = new FileInputStream(".\\\\.\\\\.\\\\test.txt"))
while (true)
int len = inputStream.read();
if (len == -1)
break;
System.out.printf("%c",len);
catch (IOException e)
e.printStackTrace();
public static void main1(String[] args) throws IOException
InputStream inputStream = null;
try
//创建实例就相当与在打开文件
inputStream = new FileInputStream("./././test.txt");
//通过逐个字节的方式把文件内容读取出来
while (true)
//read无参版本默认每次读取一个字节
//无参版本的read。返回值就是每次读取的字节
//这个返回值就是 0~255
int len = inputStream.read();
//如过读到文件末尾(EOF)就会返回 -1
if (len == -1)
break;
System.out.printf("%c",len);
catch (IOException e)
e.printStackTrace();
finally
try
//关闭
inputStream.close();
catch (IOException e)
e.printStackTrace();
InputStream只是一个抽象类,要使用还需要具体的实现类,关于InputStream实现类有很多,基本可以认为不同的输入设备上都可以对应一个InputStream类,我们现在只关心从文件中读取,所有使用FileInputStream。它继承于InputStream。
注意:如果FileInputStream的创建写到 try()的括号里,就不需要手动close了,等代码执行完毕后会自动close.只要实现了Closeable
接口就可以放到try
里.
还可以利用byte数组来读取文件内容
public static void main(String[] args)
try (InputStream inputStream = new FileInputStream("./././test.txt"))
while (true)
byte[] bytes = new byte[1024];
int len = inputStream.read(bytes);
if (len == -1)
break;
String s = new String(bytes,0,len);
System.out.println(s);
catch (IOException e)
e.printStackTrace();
利用Scanner进行字符读取
上面的读取方法,直接使用InputStream进行读取是比较麻烦的,这个时候就可以使用常用的Scanenr类来进行读取
构造方法 | 说明 |
---|---|
Scanner(InputStream is, String charset) | 使用 charset 字符集进行 is 的扫描读取 |
public static void main(String[] args)
//如果要从文件读取出中文,借出 Scanner 就可以从文件中读取
try (InputStream inputStream = new FileInputStream("./././test.txt"))
//这中写法就不用调用 Scanner的 close 方法
try (Scanner sc = new Scanner(inputStream,"utf-8"))
while (sc.hasNext())
String str = sc.next();
System.out.print(str);
catch (IOException e)
e.printStackTrace();
OutputStream
返回值 | 方法 | 说明 |
---|---|---|
void | write(int b) | 文件写入,指定字节数据 |
void | write(byte[] b) | 将b这个字符数组中的全部数据写入输出流中 |
int | write(byte[] b,int off,int len) | 将 b 这个字符数组中从 off 开始的数据写入 输出流中,一共写 len 个 |
void | close() | 闭此输出流并释放与此流相关联的任何系统资源 |
void | fluch() | 强制刷新缓冲区 |
我们知道I/O的速度是很慢的,所以,大多的OutputStream为了减少设备操作的次数,为了提高效率,就可以减少直接访问磁盘的次数。使用缓冲区,就能很好的解决这个问题。
缓冲区其实是一段内存空间(这个内存是OutputStream里自带的),当我们使用write方法来写数据的时候,并不是直接把数据写到磁盘上,而是先放到缓冲区(内存中),如果缓冲区满了,或者手动调用flush,猜真的会把数据写到磁盘上。
内存和磁盘之间的缓冲区,往往是一个内存空间
CPU和内存之间,其实也有缓冲区(L1,L2,L3,cache)
代码实例:
public static void main(String[] args)
//一旦按照 OutputStream 的方式打开文件,就会把文件的原来的内容给清空
try (OutputStream outputStream = new FileOutputStream("./././test.txt"))
/* 写入一个字符
outputStream.write('h');
outputStream.write('e');*/
//按照字节来写入
byte[] buffer = new byte[] 'a','b','c','d';
//outputStream.write(buffer);
//按照字符串来写入
String s = "你好世界 !";
//将String 转换成 byte数组,指定字符串为 UTF-8
outputStream.write(s.getBytes("UTF-8"));
//刷新缓冲区
outputStream.flush();
catch (IOException e)
e.printStackTrace();
PrintWriter
PrintWriter 类中提供了我们熟悉的 print/println/printf 方法
public static void main(String[] args)
try (OutputStream outputStream = new FileOutputStream("./././test.txt"))
//利用 PrintWriter 类来包装一下 OutputStream 然后可以更方便的进行读写
try (PrintWriter writer = new PrintWriter(outputStream))
writer.println("这是第一行");
writer.println("这是第二行");
writer.println(200+300);
writer.println("这一行是数字"+1024);
outputStream.flush();
catch (IOException e)
e.printStackTrace();
按字符读取文件(FileReader)
public static String readFile(String filePath)
StringBuilder result = new StringBuilder();
try (FileReader fileReader = new FileReader(filePath))
while (true)
//返回的是一个字符,但是不可能有负数,用int才能装下
int ch = fileReader.read();
if (ch == -1)
break;
result.append((char)ch);
catch (IOException e)
e.printStackTrace();
return result.toString();
练习
练习1:指定一个目录,扫描这个目录,找到文件名中包含了指定字符的文件.并提示用户是否要删除这个文件,根据用户的输入决定是否删除.
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
//指定一个目录,扫描这个目录,找到文件名名中包含了指定字符的文件,并让用户选择是否要删除文件
public class TestDemo1
public static void main(String[] args)
Scanner sc = new Scanner(System.in);
System.out.print("请输入一个绝对路径 -> ");
String rootPath = sc.next();
//判断该路径是否存在
File fileDir = new File(rootPath);
if (!fileDir.exists())
System.out.println("你输入的路径不正确,程序退出!");
//输入要查找的一个关键字
System.out.println("请输入一个查找的关键字:");
String keyWord = sc.next();
//递归查找
List<File> results = new ArrayList<>();
KeyWordFindFile(fileDir,keyWord,results);
//遍历结果判断是否需要删除
for (File file : results)
System.out.println("是否删除文件(Y/N)"+file.getName());
String input = sc.next();
if (input.equals("Y"))
file.delete();
System.out.println("删除成功");
/**
* 递归查找文件名中包含关键字的文件
* @param rootPath File对(绝对路径)
* @param fileNameKeyWord 查找的关键字
* @param result list
*/
private static void KeyWordFindFile(File rootPath,String fileNameKeyWord,List<File> result)
File[] files = rootPath.listFiles();
for (File file : files)
if (file.isDirectory())
//如果是目录就递归
KeyWordFindFile(file,fileNameKeyWord,result);
else if (file.isFile())
//判断文件名是否包含关键字
if (file.getName().contains(fileNameKeyWord))
result.add(file);
练习2:把文件复制到指定目录下
//把指定文件复制到另外一个路径,一定是文件
public static void main(String[] args) throws IOException
System.out.print("请输要复制文件的绝对路径 -> ");
Scanner sc = new Scanner(System.in);
String originalPath = sc.next();
//判断是否是文件
File originalFile = new File(originalPath);
if (!originalFile.isFile())
System.out.println("输入文件绝对路径错误程序退出");
return;
System.out.print("请输入文件要复制到的绝对路径(指定文件名) -> ");
String targetPath = sc.next();
File targetFile = new File(targetPath);
//判断文件是否已经存在
if (targetFile.exists())
System.out.println("文件已存在,是否替换(Y/N)");
String input = sc.next();
if (input.equals("N"))
System.out.println("复制取消");
return;
//开始复制
try (InputStream inputStream = new FileInputStream(originalFile);
OutputStream outputStream = new FileOutputStream(targetFile))
//一次性最多读取1024个字节
byte[] bytes = new byte[1024];
while (true)
int len = inputStream.read(bytes);
if (len == -1)
break;
//读多少写多少
outputStream.write(bytes,0,len);
//不flush也是可以的,在close后会自动flush
outputStream.flush();
catch (IOException e) 以上是关于Java文件IO的主要内容,如果未能解决你的问题,请参考以下文章