目录
(1)构造一个File对象
文件,一般指的都是硬盘上的文件。
硬盘(外存)和内存相比,速度上,内存比硬盘快很多,空间上,内存空间比硬盘小,成本上,内存比硬盘贵,数据的持久化存储,内存掉电后数据丢失,外存掉电后数据还在。
javaSE + 数据结构,定义变量都是在内存上申请空间,MySQL是操作硬盘
文件IO是操作硬盘操作。
路径
绝对路径:从盘符(此电脑)开始,一层一层往下找,这个过程,得到的路径。
相对路径:从给定的某个目录出发,一层一层往下找,这个过程得到的路径,一定要明确,基准目录是什么。
./:"."表示当前目录
../:".."表示当前目录的上级目录
windows文件系统上,任何一个文件,对应的路径是唯一的。
windows上可以认为,路径和文件是一一对应的,相当于一个文件的”身份标识“。
文本文件和二进制文件
文本文件,存储的是文本,文本文件就是由ASCII字符或者其他字符集编码(utf8这种)所得到的文件。
二进制文件存储的是二进制数据,没有任何字符集的限制,存储什么都行,比如.class和.exe文件就是二进制文件。
使用记事本(默认是按照文本的方式来解析显示的)打开某个文件,如果是可以看懂的文件,就是文本文件,如果是乱码,就是二进制文件。
文件操作
文件操作分为:
1.文件系统操作
创建文件,删除文件,重命名文件,创建目录
关于文件系统操作,java标准库,给我提供了一个叫做File的类。File对象是硬盘上的一个文件的”抽象“表示。
文件是存储在硬盘上的,直接通过代码操作硬盘,不太方便,就在内存中创建一个对应的对象,操作这个内存中的对象,就可以间接影响到硬盘中的文件情况了。
java中使用File类:
(1)构造一个File对象
构造过程中,可以使用绝对路径/相对路径进行初始化,这个路径指向的文件,可以是真是存在的,也可以是不存在的。
public static void main(String[] args) {
//通过File对象进行操作
File file = new File("d:/cat.jpg");//使用反斜杠
}
(2)File提供的一些方法
一些方法使用介绍:
createNewFile()和delete()
public static void main(String[] args) throws IOException {
File file = new File("./hello_word.txt");
System.out.println(file.exists());//判断file对象是否存在
System.out.println(file.isDirectory());//判断file对象代表的文件石佛偶是一个目录
System.out.println(file.isFile());//判断file代表的对象是不是一个普通文件
//创建文件
file.createNewFile();
System.out.println(file.exists());
System.out.println(file.isDirectory());
System.out.println(file.isFile());
//删除文件
file.delete();
System.out.println("删除文件之后");
System.out.println(file.exists());
}
mkdir()和mkdirs()
public static void main(String[] args) {
File file = new File("test-dir/aaa/bbb");
//file.mkdir()只能创建一级目录
file.mkdirs();//创建多级目录
}
file.list()和file.listFiles()
public static void main(String[] args) {
File file = new File("test-dir");
//列出目录下有哪些内容
String[] results = file.list();
System.out.println(Arrays.toString(results));
File[] results2 = file.listFiles();
System.out.println(Arrays.toString(results2));
}
renameTo()重命名操作
public static void main(String[] args) {
//重命名
File src = new File("./test-dir");
File dest = new File("./test222");
src.renameTo(dest);
}
2.文件内容操作(读写操作)
针对文件内容进行读和写.
路径:文件系统上的一个文件/目录的具体位置。
目录 = 文件夹
计算机的目录是有层级结构的,文件系统时以树型结构来组织文件和目录的,是一个N叉树。
文件路径,就是从树根节点出发,沿着树杈,一路向下,到达目标文件的经过的内容。
windows都是从“此电脑”起头的,表示路径的时候,可以把“此电脑“省略,直接从盘符表示开始。
针对文本文件,提供了一组类,统称为”字符流“(典型代表,Reader,Writer),读写的基本单位是字符。
针对二进制文件,提供了一组类,统称为”字节流“(典型代表,InputStream,OutputStream),读写的基本单位是字节。
字节流和字符流:比如从文件读取100个字节,可以一次性读完,也可以分着读,像接水一样,所以称为”流“。
每种流对象,分为两种:
输入的:Reader(字符流),InputSteam(字节流)
输出的:Writer(字符流),OutputStrea(字节流)
以CPU为视角,描绘输入输出:
字节流 —— InputSteam使用
InputStream 只是一个抽象类,要使用还需要具体的实现类。关于 InputStream 的实现类有很多,基本 可以认为不同的输入设备都可以对应一个 InputStream 类,我们现在只关心从文件中读取,所以使用 FileInputStream(InputStream inputStream = new FileInputStream())
1.close()(重要)
public static void main(String[] args) throws IOException {
//从文件读取
InputStream inputStream = new FileInputStream("d:/text.txt");
//关闭操作,很重要
inputStream.close();
}
关于inputStream.close()为什么重要:
首先文件里的资源,是文件描述符,关于文件描述符表,这样理解:
文件描述符表:文件描述符表记录了当前进程都打开了哪些文件,每次大家一个文件,都会在这个表里里面申请到一个位置,这个表可以当成一个数组,数组下标就是文件描述符,数组元素就是这个文件在内核中的结构体的表示。
但是这个文件描述符表的长度是有限制的,不能无休止的打开不释放,一旦满了,继续打开打开就会失败。
此时每次从文件读取内容以后,我们就需要使用inputStream.close()关闭释放资源,因为这个文件描述符表一旦满了,继续打开就会打开失败(这个问题称为文件资源泄露),很严重,如果工作时造成这个事故,可能会给个人以及公司带来损失。
所以为了避免这个close()没有写,我们可以写如下操作:
public static void main(String[] args) throws IOException {
//try with resources带有资源的try操作,
//会在try代码块结束,自动执行close关闭操作
try(InputStream inputStream = new FileInputStream("d:/text.txt")){
}
}
这里会自动关闭是因为InputStream底层实现了一个Closeable接口:
2.无参数read()读操作
关于无参数read(),每一次读都是一个字节,返回值为int.
返回值为int原因如下:
大致意思就是因为byte类型表示的范围是0 -> 255(有时候是-128 -> +127),如果读取完毕,到头了,再次read就会返回-1,由于-1在0 -> 255 范围之外,所以这里取的返回值为int.这是我的文件里的文字:
public static void main(String[] args) throws IOException {
//try with resources带有资源的try操作,会在try代码块结束,自动执行close关闭操作
try(InputStream inputStream = new FileInputStream("d:/text.txt")){
//无参数的read()默认会返回一个字节,返回值类型是int
while (true) {
int b = inputStream.read();
if (b == -1) {
//读到末尾,结束循环
break;
}
System.out.println(b);//以字节流输出
}
}
}
这是我的文件里的文字:
读入后以字节流输出(ASCII表值对应,如果文件里面是汉字,就会以字符集里面的标准输出,一般是utf8):
3.write()写操作
在文件里面写入abc:
public static void main(String[] args) throws IOException {
try(OutputStream outputStream = new FileOutputStream("d:/test.txt")) {
//写入字节
outputStream.write(97);//a
outputStream.write(98);//b
outputStream.write(99);//c
}
}
运行结果:
关于read()和write(),可以一次性读写多个字节,使用byte[]来表示,
read(),会尽可能把byte[]填满,
write,会把byte[]中所有数据都写入文件。
字符流 —— Reader(与字节流相似)
1.read()操作
public static void main(String[] args) {
try(Reader reader = new FileReader("d:/test.txt")) {
while (true) {
int c = reader.read();
if (c == -1) {
break;
}
char ch = (char)c;//字符int -> char
System.out.println(ch);
}
}catch (IOException e) {
e.printStackTrace();
}
}
运行结果:
2.write操作
try(Writer writer = new FileWriter("d:/test.txt")) {
writer.write("a");
}catch (IOException e) {
e.printStackTrace();
}
使用文件操作实现一个案例
查找某个词出现在哪些文件里,返回该文件绝对路径,代码如下:
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Scanner;
public class IODemo9 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入您要查找的目录");
//1.先让用户指定一个要搜索的根目录
File rootDir = new File(scanner.next());
if (!rootDir.isDirectory()){
System.out.println("输入有误,您输入的目录不存在");
return;
}
//让用户输入一个要查询的词
System.out.println("请输入一个要查询的词");
String word = scanner.next();
//3.递归的方式进行目录/文件的遍历
scanDir(rootDir,word);
}
private static void scanDir(File rootDir,String word) {
//列出当前的rootDir中的内容,没有内容,直接递归结束
File[] files = rootDir.listFiles();
if (files == null) {
//当前rootDir是一个空的目录
//没有必要递归了
return;
}
//目录里面有内容,就便利目录中的每个元素
for (File f : files) {
System.out.println("当前搜索到:" + f.getAbsolutePath());
if (f.isFile()) {
//如果是普通文件
//打开晚间,读取内容看是否包含上面的关键词
String content = readFile(f);
if (content.contains(word)) {
System.out.println(f.getAbsolutePath() + "包含要查找的关键字");
}
}else if(f.isDirectory()) {
//是目录
scanDir(f,word);
}else {
//既不是普通文件也不是目录,直接跳过
continue;
}
}
}
private static String readFile(File f) {
//读取文件的整个内容,返回
//使用字符流读取,因为匹配的是字符串,直接按照字符流处理
StringBuilder stringBuilder = new StringBuilder();
try (Reader reader = new FileReader(f)){
//一次制度一个字符,把督导的结果给拼装到StringBuilder中,统一转成String
while(true) {
int c = reader.read();
if (c == -1) {
break;
}
stringBuilder.append((char)c);
}
}catch (IOException e) {
e.printStackTrace();
}
return stringBuilder.toString();
}
}