1、File类
1、概念:
java.io.File类是文件和目录路径名的抽象表示。作用在于:通过路径字符串表示操作系统中的文件或文件夹。
2、构造方法
File(String pathname) 通过【路径名】创建一个File对象,这个File对象可以表示文件也可以表示文件夹
File(String parent, String child) 通过【父路径】和【子路径】创建File对象
File(File parent, String child) 通过【父路径File对象】和【子路径】创建File对象
(Ps:构造File类的过程中,并不会创建新的文件夹和文件)
3、利用File类的方法创建文件夹和文件
1、File类的方法:
boolean createNewFile() 创建新文件, 如果创建成功返回true
boolean mkdir() 创建一个文件夹, 如果创建成功返回true
boolean mkdirs() 创建多级文件夹, 如果创建成功返回true
2、注意:
WINDOWS中文件名不区分大小写
WINDOWS中路径分隔符可以写反斜杠\\,也可以写正斜杠/
public static void main(String[] args) throws IOException {
test3();
}
// boolean mkdirs() (推荐使用)创建多级文件夹, 如果创建成功返回true
public static void test3() {
File file = new File("C:/MyFileTest/666/777/888");
boolean b = file.mkdirs();
System.out.println(b);
}
// boolean mkdir() 创建一个文件夹, 如果创建成功返回true
public static void test2() {
//文件名不区分大小写,所以下面两天语句只执行前面那条ccc
// File file = new File("C:\\MyFileTest\\ccc");
// File file = new File("C:\\MyFileTest\\CCC");
File file = new File("C:/MyFileTest/ddd");
boolean b = file.mkdir();
System.out.println(b);
}
// boolean createNewFile() 创建新文件,如果创建成功返回true
public static void test1() throws IOException {
File file = new File("C:\\MyFileTest\\123.txt");
boolean b = file.createNewFile();
System.out.println(b);
}
4、利用File类的方法删除文件夹和文件
1、File类的方法:
boolean delete() 删除文件或文件夹,删除成功返回true
2、注意:
删除就没有了.不会在回收站里面
如果文件加里面有内容,需要先删除文件夹里面的内容,再删除空文件夹
// boolean delete() 如果文件加里面有内容,需要先删除文件夹里面的内容,再删除空文件夹
//否则,会删除失败。
public static void test3() {
File in = new File("C:\\MyFileTest\\ddd\\aaa");
System.out.println("删除里面内容: " + in.delete());
File file = new File("C:\\MyFileTest\\ddd");
boolean b = file.delete();
System.out.println("删除文件夹: " + b);
}
5、路径分类
1、绝对路径:
从盘符开始的就是绝对路径
C:/MyFileTest/abc/aaa
C:/MyFileTest/abc/bbb
2、相对路径:(找到“相对的”参照路径)
没有从盘符开始的就是相对路径
参照: C:/MyFileTest/abc/
aaa -> 完整路径: C:/MyFileTest/abc/aaa
bbb -> 完整路径: C:/MyFileTest/abc/bbb
3、工程路径
即idea相对路径的参照。(idea软件的左上角)
以下代码可以打印出工程路径
public class demo4 {
public static void main(String[] args) {
File file = new File("aaa");
System.out.println(file.getAbsoluteFile());
}
}
6、File的获取功能
1、File类的方法
String getAbsolutePath() 返回绝对路径
String getPath() 返回创建File对象时的路径
String getName() 返回路径的名称(返回文件或者文件夹的名称)
long length() 返回文件的长度(只能获取文件的长度,若是文件夹,长度永远等于0;长度即文件大小,单位是字节)。
public static void main(String[] args) {
File file = new File("day06\\abc\\123.txt");
System.out.println(file.getAbsoluteFile());E:\IdeaProjects\Pratice-code\day06\abc\123.txt
System.out.println(file.getPath());//day06\abc\123.txt
System.out.println(file.getName());//123.txt
System.out.println(file.length());//35
}
7、File的判断功能
File类:
boolean isDirectory() 判断是否是文件夹,如果是返回true
boolean isFile() 判断是否是文件,如果是返回true
boolean exists() 判断是否存在(文件或者文件夹),如果存在返回true
public static void main(String[] args) {
// test1();
// test2();
test3();
}
// boolean exists() 判断是否存在,如果存在返回true
public static void test3() {
// File file = new File("C:\\MyFileTest\\123.txt");
// File file = new File("C:\\MyFileTest\\aaa");
File file = new File("C:\\MyFileTest\\xxx");
System.out.println(file.exists());
}
// boolean isFile() 判断是否是文件,如果是返回true
public static void test2() {
// File file = new File("C:\\MyFileTest\\123.txt");
File file = new File("C:\\MyFileTest\\aaa");
System.out.println(file.isFile());
}
// boolean isDirectory() 判断是否是文件夹,如果是返回true
public static void test1() {
// File file = new File("C:\\MyFileTest\\aaa");
File file = new File("C:\\MyFileTest\\123.txt");
System.out.println(file.isDirectory());
}
8、File的目录遍历功能
1、目录遍历:
目录的遍历就是显示文件夹中的内容(就是双击文件夹)
2、File类中的方法:
String[] list() 列出文件夹里面的所有内容,返回文件名数组
File[] listFiles() (常用) 列出文件夹里面的所有内容,返回File对象数组
3、注意:
文件不能调用list功能(会返回null值)
// 文件不能调用list功能
public static void test3() {
File file = new File("C:\\MyFileTest\\123.txt");
File[] files = file.listFiles();
System.out.println(files); // 返回null
}
// File[] listFiles() (常用)列出文件夹里面的所有内容,返回File对象数组
public static void test2() {
File file = new File("C:\\MyFileTest\\aaa");
// 列出文件夹里面的所有内容,返回File对象数组
File[] files = file.listFiles();
for (File f : files) {
System.out.println(f);
}
}
// String[] list() 列出文件夹里面的所有内容,返回文件名数组
public static void test1() {
File file = new File("C:\\MyFileTest\\aaa");
// 列出文件夹里面的所有内容,返回文件名数组
String[] list = file.list();
// 遍历数组
for (String name : list) {
System.out.println(name);
}
}
2、递归
1、概念:
方法自己调用自己
2、应用递归时的注意事项
1.递归要有出口(要有停止递归的条件)
2.递归次数不能够太多(在有停下来的条件的同时,要保证参数少到不回发生栈溢出错误:StackOverError)
public static void main(String[] args) {
int sum = getSum(5);
System.out.println(sum);
}
/*
规律:1到n的和 = n + 1到n-1的和
出口:当n=1时,返回1
getSum: 参数写几,就是计算1到几的和
*/
public static int getSum(int n) {
// 【出口】:当n=1时,返回1 **********************************重要!!!
if (n == 1) {
return 1;
}
// 规律:1到n的和 = n + 1到n-1的和
return n + getSum(n-1);
}
// 使用for循环求1-5的和: 1 + 2 + 3 + 4 + 5.txt
public static void test01() {
int sum = 0;
for (int i = 1; i <= 5; i++) {
sum += i;
}
System.out.println("sum = " + sum);
}
3、递归和File类综合案例
/*
目标:列出文件夹中的所有java文件
讲解:
步骤:
1.定义一个File对象,表示要列出的文件夹
2.定义一个方法显示dir文件夹里面的java文件:
listJava(File dir)
3.列出dir文件夹的所有内容
4.遍历每个File对象
5.txt.如果是文件,并且是.java结尾的文件就打印
6.如果是文件夹,调用listJava(文件夹)
小结:
以后要操作文件夹,并且文件夹里面还有文件夹,就考虑使用【递归】****************重要!
*/
public class Demo10 {
public static void main(String[] args) {
// 1.定义一个File对象,表示要列出的文件夹
File file = new File("E:\1a黑马java\黑马java\基础班\源程序\Day02");
listJava(file);
}
// 2.定义一个方法显示dir文件夹里面的java文件:
public static void listJava(File dir) {
// 3.列出dir文件夹的所有内容
File[] files = dir.listFiles();
// 4.遍历每个File对象
for (File file : files) {
if (file.isFile()) {
// 5.txt.如果是文件,并且是.java结尾的文件就打印
if (file.getName().endsWith(".java")) {
System.out.println(file);
}
} else {
// 6.如果是文件夹,调用listJava(文件夹)------>【递归】
listJava(file);
}
}
}
}
3、I/O流
1、IO流概念:
【对比】:File的功能,操作文件或文件夹如新建,删除,获取信息,(相当于我们图形界面对文件进行鼠标右键操作)
把数据在内存和外部设备之间的流动叫做IO流。已内存为基准,Input/Output 输入/输出流,即流向内存是输入流,流出内存的输出流
2、IO流的作用
通过IO流我们可以读取文件里面的数据,还可以往文件里面写数据。
而对文件的操作很重要。因为之前保存数据使用集合或数组, 集合或数组保存在内存中的.内存一旦断电,就没有了.(内存是临时性存储)。如果想将数据永久存储.需要将数据保存在文件中.
3、IO流的分类
(1)按照数据流向,
分为输入流(数据从设备流向内存)和输出流(数据从内存流向设备)
(2)按操作的类型,
分为字节流:(操作的单位是字节)和 字符流:(操作的单位是字符,方便我们操作字符)
4、根据分类,有四个IO顶级父类
IO流的顶级父类:
字节流 字符流
输入流 字节输入流InputStream 字符输入流Reader
输出流 字节输出流OutputStream 字符输出流Writer
PS:特点:这四个类都是抽象类,使用的时候用的是其子类
5、FileOutputStream类:字节输出流
(1)概念:
其父类是OutputStream,中文名为字节输出流
(2)构造方法:
创建流的时候,如果没有对应的文件,则会创建新文件;
有对应的文件,则要看具体方法,判断其是否会覆盖原来的文件进行重新写入(非追加写)和追加写。
FileOutputStream(String name) 创建一个文件字节输出流,流中的数据会流入指定的文件中
FileOutputStream(File file) 创建一个文件字节输出流,流中的数据会流入指定的文件中
(3)IO流的使用步骤:
1.创建IO流
2.读写数据
3.关闭流
(4)普通方法-------往流中写入一个字节数据
非追加写
void write(int b) 将一个字节写入流中
public static void main(String[] args) throws IOException, InterruptedException {
// FileOutputStream(String name) 创建一个文件字节输出流,流中的数据会流入指定的文件中
// FileOutputStream fos = new FileOutputStream("day09demo/abc/2.txt");//工程路径...
// FileOutputStream(File file)
File file = new File("day09demo/abc/3.txt");//工程路径...
FileOutputStream fos2 = new FileOutputStream(file);
// void write(int b) 将一个字节写入流中
// 我们要写字节byte,参数是int,不怕.
fos2.write(97);
// IO流使用完需要关闭
fos2.close();
//(字节输出流相当于往文件中“伸出”了一根管子,一直占用着这个文件,
// 必须关闭才能使该文件“独立”而不被占用,不然会导致“别人”无法对该文件进行操作)
// 模拟程序一直被占用(程序一直在运行)
// Thread.sleep(10000);//此时,2.txt文件没办法进行任何操作。
}
(5)普通方法-----往流中写入一个字节数组数据
非追加写
void write(byte[] b) 将字节数组中的数据写入流中
void write(byte[] b, int off, int len) 将字节数组中的部分数据写入流中
// int off: 从输入哪个索引开始写
// int len: 写多少个数据
public static void main(String[] args) throws IOException {
// 1.创建文件字节输出流
FileOutputStream fos = new FileOutputStream("day09demo/abc/4.txt");
// 2.写数据
// void write(byte[] b) 将字节数组中的数据写入流中
byte[] buf = new byte[] {65, 66, 67, 68, 69};
// fos.write(buf);
// void write(byte[] b, int off, int len) 将字节数组中的部分数据写入流中
// int off: 从输入哪个索引开始写
// int len: 写多少个数据
// fos.write(buf, 2, 3);
// 将字符串转成字节数组-----> 字符串.getBytes();
byte[] bytes = "你好".getBytes();
fos.write(bytes);
// 3.关闭流
fos.close();
}
(6)普通方法-------往流中追加写一个字节数据
前述的方法在写数据时是会删除以前的数据,进行重新写入。
FileOutputStream(File file, boolean append)
FileOutputStream(String name, boolean append)
当append设置为true时,就不会删掉以前的,在之前的基础上追加写入数据
public static void main(String[] args) throws IOException {
// FileOutputStream(String name, boolean append)
FileOutputStream fos = new FileOutputStream("day09demo/abc/4.txt", true);
fos.write("\r\n".getBytes());
fos.write(66);
fos.write(65);
fos.close();
}
6、FileInputStream类:字节输入流
(1)概念:
其父类是InputStream,中文名为字节输入流
(2)构造方法
FileInputStream(String name) 创建文件字节输入流,读取指定文件中的内容
FileInputStream(File file) 创建文件字节输入流,读取指定文件中的内容
(3)普通方法-------往流中读入一个字节数据
int read() 读取一个字节,返回读取到的字节数据,返回int类型数据
如何循环读取一个字节
int b;
while ((b = fis.read()) != -1) {
System.out.print((char) b);
}
public static void main(String[] args) throws IOException {
// 1.创建文件字节输入流
// FileInputStream(String name) 创建文件字节输入流,读取指定文件中的内容
// FileInputStream fis = new FileInputStream("day09demo/abc/4.txt");
// 2.读取数据:hello
// int read() 读取【下一个】字节数据
/*int b = fis.read();
System.out.println((char) b); // h
b = fis.read();
System.out.println((char) b); // e
b = fis.read();
System.out.println((char) b); // l
b = fis.read();
System.out.println((char) b); // l
b = fis.read();
System.out.println((char) b); // o
b = fis.read();
System.out.println(b); // -1 下一个字节为空时,返回值为-1 */
// 以上代码是重复代码,我们改用while循环,循环的终止条件是-1
FileInputStream fis = new FileInputStream("day09demo/abc/4.txt");
// 定义一个变量,保存读取到的数据
int b;
// 1.fis.read() 读取一个字节
// 2.b = fis.read() 将读取的数据保存到b中
// 3.b != -1 判断b是否为-1,如果不是-1说明读取到数据
while ((b = fis.read()) != -1) {
// 读取到了数据
System.out.print((char) b);
}
// 3.关闭流
fis.close();
}
(4)普通方法-------往流中读入一个字节数组的数据
int read(byte[] b) 读取多个数据,多个数据放到参数的byte数组中,返回读取到的个数
如何循环读取一个字节的数组数据
int len;
byte[] buf = new byte[1024 * 4]; // 通常写1024的整数倍 1024个字节是1kb
while ((len = fis.read(buf)) != -1) {
System.out.print(new String(buf, 0, len));
}
一次读取一个字节的数组好处:
IO操作文件时实际上是外存的访问,外存数据的读取,速度是比较慢的。一次读取一个字节数组,相比于一次读取一个字节,总量上减少了读取次数,效率提高了。
public static void main(String[] args) throws IOException {
// int read(byte[] b) 读取多个数据,多个数据放到参数的byte数组中,返回读取到的个数
//字符串的构造方法之一:String str = new String(buf);
/*
FileInputStream fis = new FileInputStream("day09demo/abc/4.txt");
byte[] buf = new byte[3];
int len = fis.read(buf);
System.out.println("长度: " + len); // 3
System.out.println("内容: " + new String(buf)); // hel
len = fis.read(buf);
System.out.println("长度: " + len); // 3
System.out.println("内容: " + new String(buf)); // low
len = fis.read(buf);
System.out.println("长度: " + len); // 3
System.out.println("内容: " + new String(buf)); // orl
len = fis.read(buf);
System.out.println("长度: " + len); // 1
//(只读取了d,所以数据只覆盖了第一个,后两个没有被覆盖,仍然是前面的rl)
System.out.println("内容: " + new String(buf)); // drl
len = fis.read(buf);
//当下一个将要读取的地方是没有内容可读的时候,实际上是访问到了“文件结束标记”。
System.out.println("长度: " + len); // -1 没有读取到内容返回-1
*/
// 我们发现以上是重复代码,故可使用while来解决
FileInputStream fis = new FileInputStream("day09demo/abc/4.txt");
// 定义变量,保存读取到的数量
int len;
// 定义数组,保存读取到的数据
byte[] buf = new byte[1024 * 4]; // 【通常写1024的整数倍 1024个字节是1kb】
// 1.fis.read(buf) 使用字节读取数据,读取到的数据放到参数的数组中
// 2.len = fis.read(buf) 将读取到的个数保存到len变量中
// 3.len != -1 判断读取到的个数是否为-1,如果不是-1说明读取到了内容
while ((len = fis.read(buf)) != -1) {
// new String(buf, 0, len) 将数组中的【部分数据】转成字符串
// 第一个参数,数组的哪个位置开始转
// 第二个参数,转多少个数据
System.out.print(new String(buf, 0, len));
}
fis.close();
}
知识回顾:字符串和字符数组之间的转换关系
/*
1.String转byte[]使用哪个方法?
byte[] bytes = "hello".getBytes();
2.byte[]转String使用哪个方法?
String str = new String(buf);
String str = new String(buf, 0, len) 将数组中的【部分数据】转成字符串
// 第一个参数,指定字节数组
// 第二个参数,数组的哪个位置开始转
// 第三个参数,转多少个数据
*/
public static void main(String[] args) {
// byte[] 转成 String
byte[] buf = new byte[] {97, 98, 99, 100};
String str = new String(buf);
String str2 = new String(buf,0,3);
System.out.println("str = " + str); // str = abcd
System.out.println("str2 = " + str2);
// String 转成 byte[]
byte[] bytes = "hello".getBytes();
System.out.println(Arrays.toString(bytes));
}
(5)案例:图片复制
/*
目标:使用字节流将 "day09demo/abc/xyz.png" 复制到 "c:/MyFileTest/xyz.png"
图片是以字节的方式存储在文件中
讲解:
复制文件的步骤:
1.创建文件字节输入流
2.创建文件字节输出流
3.循环读写文件
4.关流
小结:
1.字节流复制文件步骤?
1.创建文件字节输入流
2.创建文件字节输出流
3.循环读写文件
4.关流
*/
public class Demo19 {
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
// copy01(); // 603
copy02(); // 2
long end = System.currentTimeMillis();
System.out.println("消耗时间: " + (end - start));
}
// 循环读写文件(一个字节数组)
public static void copy02() throws IOException {
// 1.创建文件字节输入流
FileInputStream fis = new FileInputStream("day09demo/abc/xyz.png");
// 2.创建文件字节输出流
FileOutputStream fos = new FileOutputStream("c:/MyFileTest/xyz2.png");
// 3.循环读写文件(一个字节数组)
int len;
byte[] buf = new byte[1024];
long start = System.currentTimeMillis();
while ((len = fis.read(buf)) != -1) {
fos.write(buf, 0, len);
}
long end = System.currentTimeMillis();
System.out.println(end - start);
// 4.关流
fis.close();
fos.close();
}
// 循环读写文件(一个字节)
public static void copy01() throws IOException {
// 1.创建文件字节输入流
FileInputStream fis = new FileInputStream("day09demo/abc/xyz.png");
// 2.创建文件字节输出流
FileOutputStream fos = new FileOutputStream("c:/MyFileTest/xyz.png");
// 3.循环读写文件(一个字节)
int b;
long start = System.currentTimeMillis();
while ((b = fis.read()) != -1) {
fos.write(b);
}
long end = System.currentTimeMillis();
System.out.println(end - start);
// 4.关流
fis.close();
fos.close();
}
}
7、FileReader类:字符输入流
(1)概念:
其父类是Reader,中文名为字符输入流
(2)构造方法
FileReader(String fileName) 创建一个新的 FileReader 读取指定文件中的字符
FileReader(File file) 创建一个新的 FileReader 读取指定文件中的字符
(3)普通方法:
和字节输入流相似
int read() 读一个字符, 返回值是读取到的字符
int read(char[] cbuf) 将字符读入数组,返回读取的字符数量
public static void main(String[] args) throws IOException {
/*FileReader fr = new FileReader("day09demo/abc/6.txt");
int ch = fr.read();
System.out.println((char)ch); // 你
ch = fr.read();
System.out.println((char)ch); // 不
ch = fr.read();
System.out.println((char)ch); // 要
ch = fr.read();
System.out.println((char)ch); // 乱
ch = fr.read();
System.out.println((char)ch); // 来
ch = fr.read();
System.out.println(ch); // -1*/
// 循环读取一个字符
/*FileReader fr = new FileReader("day09demo/abc/6.txt");
int ch; // 定义变量保存读取到的字符
while ((ch = fr.read()) != -1) {
System.out.print((char)ch);
}*/
// 循环读取一个字符数组
FileReader fr = new FileReader("day09demo/abc/6.txt");
int len; // 定义变量保存读取到的数量
char[] chs = new char[3];
while ((len = fr.read(chs)) != -1) {
System.out.print(new String(chs, 0, len));
}
fr.close();
}
8、FileWriter类:字符输出流
(1)概念:
其父类是Writer,中文名为字节输出流
(2)构造方法
FileWriter(String fileName) 创建一个文件字符输出流,往指定的文件写数据
FileWriter(File file) 创建一个文件字符输出流,往指定的文件写数据
(3)普通方法
void write(int c) 写一个字符
void write(char[] cbuf) 写入一个字符数组。
void write(char[] cbuf, int off, int len) 写入字符数组的一部分。
特有:
void write(String str) 写一个字符串
void write(String str, int off, int len) 写一个字符串的一部分。
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("day06/abc/7.txt");
// 2.写数据
// void write(int c) 写一个字符
fw.write('爱');
// void write(char[] cbuf) 写入一个字符数组。
char[] chs = new char[] {'我', '想', '要', '个', '女', '同', '桌'};
fw.write(chs);
// void write(char[] cbuf, int off, int len) 写入字符数组的一部分。
fw.write(chs, 2, 4);
// void write(String str) 写一个字符串
fw.write("你做梦");
String sb = "我很随便";
// void write(String str, int off, int len) 写一个字符串的一部分。
fw.write(sb, 2, 2);
// flush:刷新缓冲区,将缓冲区的数据写入文件
// flush后还可以接着写数据
fw.flush();
fw.write("我再来一次");
// fw.flush();
// 3.关闭流
// close:关闭流的时候也会刷新一下
// close后不能再写数据
fw.close();
//fw.write("我又再来一次");//IOException: Stream closed
}
注意flush和close之间的差别!!