介绍Java中对文件的系统操作和io(读写)
目录
2)FileInputStream( InputStream 的实现类之一:从文件中读取)
一、认识文件
1.文件概念:
针对硬盘这种持久化存储的I/O设备,进行数据保存时,往往不是保存成一个整体,而是独立成一个个的单位进行保存,这个独立的单位就被抽象成文件的概念.
2.文件组织管理:
文件会按照层级结构进行组织 , 也就是树形结构组织。专门用来存放管理信息的特殊文件,也就是所谓文件夹(folder)或者目录(directory)的概念。
3.文件路径:
用以定位文件(Windows中路径与文件唯一对应)。
1)绝对路径:
从树型结构的角度来看,一条从根开始,一直到达的结点的路径,被称为文件的绝对路径(absolute path),(windows,即从盘符开始,一直到文件的路径。)
例如:
2)相对路径:
从任意(父)结点(指定一个基准目录)出发到到达结点称为文件的相对路径(relative path)。
例如:
(. 表示当前结点,即当前目录 , .. 表示父结点,即上一级文件目录。斜杠/,或者反斜杠\,用来做路径分隔符。反斜杠仅适用于Windows,代码中需要用转义字符\\)
4.文件类型:
根据文件保存数据的不同,分为不同的类型。一般简单的划分为文本文件和二进制文件,分别指代保存被字符集编码的文本和按照标准格式保存的非被字符集编码过的文件。
1)文本文件:
存储遵守ascii码,utf8,或其他字符集编码的字符。(可以用记事本打开)
2)二进制文件:
存储二进制数据。(用记事本打开会乱码)
(Windows 操作系统上,会按照文件名中的后缀来确定文件类型以及用打开该类型文件的默认打开程序来打开文件。)
二、Java中操作文件
1.文件系统操作(File类):
File类(Java.Io.File),File对象是对硬盘上的文件的“抽象”表示,在内存中创建一个对应的对象,操作这个内存的对象,可以间接影响到硬盘上对应的文件。
1)File类属性:
修饰符及类型 | 属性 | 说明 |
static String | pathSeparator | 与系统相关的默认名称分隔符,String 类型的表示 |
static char | pathSeparator | 与系统相关的默认名称分隔符,char 类型的表示 (在UNIX系统上,该字段的值为 |
2)File类构造方法:
(创建一个File对象,硬盘上不一定有对应的文件。)
方法签名 | 说明 |
File(File parent, String child) | 根据父目录 + 孩子文件路径,创建一个新的 File 实例 |
File(String pathname) | 根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者 相对路径 |
File(String parent, String child) | 根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用 路径表示 |
3)File类方法:
修饰符及返回类型 | 方法签名 | 说明 |
String | getParent() | 返回 File 对象的父目录文件路径 |
String | getName() | 返回 FIle 对象的纯文件名称 |
String | getPath() | 返回 File 对象的文件路径 |
String | getAbsolutePath() | 返回 File 对象的绝对路径 |
String | getCanonicalPath() | 返回 File 对象的修饰过的绝对路径 |
boolean | exists() | 判断 File 对象描述的文件是否真实存在 (创建一个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) | 重命名File对象代表的文件. (dest名字pathname里面包含着文件路径(所在位置)和文件的名字) 比如C:\Program Files (x86)\Google\(前面是所在位置)名字) 如果前面路径一样仅仅修改名字,就是对文件改了个名字 修改名字前面的路径,就相当于移动文件剪切粘贴到其他的地方. |
boolean | canRead() | 判断用户是否对文件有可读权限 |
boolean | canWrite() | 判断用户是否对文件有可写权限 |
2.文件内容的读写--数据流
针对文本文件读写的一组类,统称“字符流”(Reader,Writer),读写基本单位为字符。
针对二进制文件的读写一组类,统称“字节流”(InputStream,OutputStream),读写基本单位为字节。
(Reader,InputStream,输入流。Writer,OutputStream,输出流。输入,输出是以cpu为基准的。)
这里介绍InputStream和OutputStream,(Reader,Writer的用法也类似如此)。
1)InputStream
InputStream 一个抽象类,要使用还需要具体的实现类。关于 InputStream 的实现类有很多,基本
可以认为不同的输入设备都可以对应一个 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() | 关闭字节流 |
注意close方法:输入输出流使用完之后必须使用close方法关闭。否则可能会造成文件资源泄露。这里的文件资源主要指文件描述符,由第一篇文章进程那可知,进程每打开一个文件,都会在文件描述符表(可当成一个数组,数组下标就是文件描述符,数组元素就是这个文件在内核中的结构体的表示)中申请一个位置,但是这个表的长度是有限的,如果表满了,再继续打开文件,则会打开失败。
(也可使用try-with-resources 语句自动执行close操作关闭资源。
try-with-resources 语句确保了每个资源在try代码块结束时关闭。所有实现java.lang.AutoCloseable 接口(其中,它包括实现了 java.io.Closeable 的所有对象),可以使用作为资源。
代码示例:
//try后括号里放资源。
try (InputStream is = new FileInputStream("Lin.txt")) {
}
//try代码块执行完后会自动释放资源
)
2)FileInputStream( InputStream 的实现类之一:从文件中读取)
其构造方法:
签名 | 说明 |
FileInputStream(File file) | 利用 File 构造文件输入流 |
FileInputStream(String name) | 利用文件路径构造文件输入流 |
(但是对字符类型直接使用 InputStream 进行读取是非常麻烦且困难的,可以使用 Scanner 类
构造方法 | 说明 |
Scanner(InputStream is, String charset) | 使用 charset 字符集进行 is 的扫描读取 |
代码示例:
try (InputStream is = new FileInputStream("Lin.txt")) {
try (Scanner scanner = new Scanner(is, "UTF-8")) {
while (scanner.hasNext()) {
String s = scanner.next();
}
}
)
3)OutputStream
OutputStream 同样只是一个抽象类,要使用还需要具体的实现类.
方法:
修饰符及 返回类型 | 方法签名 | 说明 |
void | write(int b) | 写入要给字节的数据 |
void | write(byte[] b) | 将 b 这个字符数组中的数据全部写入 os 中 |
int | write(byte[] b, int off, int len) | 将 b 这个字符数组中从 off 开始的数据写入 os 中,一共写 len 个 |
void | close() | 关闭字节流 |
void | flush() | 不要忘记flush() 重要: I/O 的速度是很慢的,所以,大多的 OutputStream 为了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写入设备中,这个区域一般称为缓冲区。但可能造成一个结果,就是写的数据可能会遗留一部分在缓冲区中。需要在最后或者合适的位置, |
3.Java操作文件代码示例
扫描指定目录,并找到名称或者内容中包含指定字符的所有普通文件(不包含目录)
/**
* Created with IntelliJ IDEA.
* Description:
* User: 林
* Date: 2023-04-22
* Time: 10:06
*/
import java.io.*;
import java.util.*;
//java操作文件的代码示例:
// 扫描指定目录,并找到名称或者内容中包含指定字符的所有普通文件(不包含目录)
public class Main {
public static void main(String[] args) throws IOException {
//输入要扫描的路径
System.out.println("请输入要扫描的路径:");
Scanner sc=new Scanner(System.in);
String rootPath=sc.next();
//检查输入的路径是否合法
if(rootPath==null||rootPath.equals("")){
System.out.println("路径输入不合法(不能为空)");
return;
}
//根据输入的路径,实例化一个File对象.
File rootDirectory=new File(rootPath);
//检查输入的路径是否存在及输入的路径是否是一个目录。
if(!rootDirectory.exists()){
System.out.println("输入的路径不存在");
return;
}
if(!rootDirectory.isDirectory()){
System.out.println("输入的路径不是一个目录");
return;
}
//输入要查找的字符.
System.out.println("请输入要查找的字符");
String findString=sc.next();
//检查输入的要查找字符是否合法
if(findString==null||findString.equals("")){
System.out.println("字符输入不合法(不能为空)");
return;
}
//然后遍历目录来逐个文件查找字符,把包含要查找字符的文件保存.
//用个顺序表保存文件.
List<File> fileList=new ArrayList<>();
//写一个遍历目录方法.
scan_directory(rootDirectory,findString,fileList);
//输出包含要查找字符的文件路径
if(fileList.isEmpty()){
System.out.println("没有文件包含要查找字符");
}else{
int size=fileList.size();
System.out.println("找到"+size+"个文件如下:");
for (int i = 0; i < size; i++) {
System.out.println(fileList.get(i).getAbsoluteFile());
}
}
}
//遍历目录.
private static void scan_directory(File rootDirectory,String findString,List<File> fileList) throws IOException {
//获取目录下所有文件.
File[] files=rootDirectory.listFiles();
//检查目录是否为空.
if(files==null||files.length==0){
return;
}
//for循环遍历
for (int i = 0; i < files.length; i++) {
//是目录则递归
if (files[i].isDirectory()) {
scan_directory(files[i],findString,fileList);
}else{//是文件则查找其文件名或内容.
if(files[i].getName().contains(findString)){
fileList.add(files[i]);
}else{
//再写一个方法,查找文件内容.
int ret=scan_file(files[i],findString);
//返回1,找到,-1,找不到.
if(ret==1){
fileList.add(files[i]);
}
}
}
}
}
//查找文件内容
private static int scan_file(File file,String findSting) throws IOException {
//用StringBuffer存储读取的内容.
StringBuffer stringBuffer=new StringBuffer();
//输入流
try(InputStream inputStream=new FileInputStream(file)){
try(Scanner sc=new Scanner(inputStream,"UTF-8")){
// 读取每一行
while (sc.hasNext()) {
// 一次读一行
stringBuffer.append(sc.nextLine());
// 加入一行的结束符
stringBuffer.append("\r\n");
}
}
}
if(stringBuffer.indexOf(findSting)!=-1){
return 1;
}else{
return -1;
}
}
}