File类
一、扩展
1.在电脑中,什么是文件?什么是文件夹?
一般情况下,带有后缀名的是文件,不带后缀名的是文件夹
2.文件或者文件夹存储在哪里?
存储在硬盘上 //C盘 D盘。。。。
3.我们怎么能知道文件的属性信息?
右键 ------ 属性
4.我们说万物皆对象,那么在Java中用哪个类来表示文件或者文件夹呢?
File类
二、File类的构造方法
1.File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
//参数string指的就是你要表示的文件或者文件夹的路径
2.File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例。
//参数有两个 第一个string:父路径名 第二个string:自路径名
3.File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例。
//第一个参数File 第二个参数:String
//相比较于第二个构造方法而言,parent可以调用File类的相关方法
//问题:
为什么File类没有无参构造?
因为我们的电脑里有千千万万个文件和文件夹,如果你不给路径,那么JVM就不知道你创建的File对象指的到底是哪个文件
//注意事项
1.目录之间的分隔符 \ 在引号中必须写两个\\,如果使用户向左的斜杠/ 那么只需要写一个
//在Java中,字符串中第一次出现的 \ 代表的是转义的意思,转的是紧跟在\后面的那个字符。
File f1 = new File("D:\\a.txt");
File f2 = new File("D:/a.txt");
2.目录的盘符是不区分大小写的
File f1 = new File("D:\\a.txt");
File f1 = new File("d:/a.txt");
三、File类的创建功能
1.public boolean createNewFile()当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空"文件" //创建的是文件
代码实现:
File f1 = new File("d:/qwe/a.txt"); //注意:要想创建a.txt,必须先保证这个文件所在的上一级文件夹是存在的
System.out.println(f1.createNewFile());
2.public boolean mkdir() 创建由此抽象路径名命名的"目录" //创建的是单级文件夹
// mk:make dir: directory
代码实现:
File f1 = new File("D:\\bcd");
boolean mkdir = f1.mkdir();
System.out.println(mkdir);
3.public boolean mkdirs() 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录 //创建的是多级文件夹
代码实现:
File f2 = new File("D:/bcd/qwe");
System.out.println(f2.mkdirs());
四、File类的判断和获取功能
1.public boolean isDirectory() 测试此抽象路径名表示的File是否为目录 //判断是否是文件夹
2.public boolean isFile() 测试此抽象路径名表示的File是否为文件 //判断是否是文件
3.public boolean exists() 测试此抽象路径名表示的File是否存在 //判断file对象指向的文件是否真实存在
4.public String getAbsolutePath() 返回此抽象路径名的"绝对路径"名字符串
//绝对路径:指的是带盘符的路径
代码实现:
File f1 = new File("D:\\bcd\\a.txt");
System.out.println(f1.getAbsolutePath());
5.public String getPath() 将此抽象路径名转换为路径名字符串
//获取的是创建对象的时候,构造方法中传递的字符串
6.public String getName() 返回由此抽象路径名表示的文件或目录的名称 //获取的是文件或者文件夹的名称
7.public String[] list() 返回此抽象路径名表示的目录中的文件和目录的名称字符串数组//获取文件夹下面所有的文件和者文件的名称
8.public File[] listFiles() 返回此抽象路径名表示的目录中的文件和目录的File对象数组 获取文件夹下面所有的文件和者文件的对象
五、File类的删除功能
1.绝对路径和相对路径问题 //☆☆☆☆☆
绝对路径:指的是带盘符的路径
相对路径:不带盘符的路径//☆☆☆☆☆
//到底相对于谁?
相对的是项目(在项目的下面),不是module,和module是平级关系
项目(project)和模块(module)的区别?
一个项目下可以有多个模块
2.删除的相关方法
public boolean delete() 删除由此抽象路径名表示的文件或目录
//注意事项:
(1).在删除文件夹的时候,一定要保证该文件夹是空的
File f1 = new File("D:/bcd"); //必须保证bcd文件夹为空,这个时候才能删除掉
System.out.println(f1.delete());
(2)java中的删除不走回车站
1. File f1 = new File("G:\\a.txt"); 为什么这段代码运行后,g盘不会出现这个a.txt文件 f1.createNewFile();
而这段代码运行后才会产生这个a.txt文件 可不可以理解为 第一句是 告诉jvm我想要处理一个叫a.txt的文件
第二句是 我确定要创建它了 我感觉如果格式是这样我就可以很容易理解了
(但这个是不对的) File f1 = new File(); f1.createNewFile("G:\\a.txt");
2.在创建File对象时,相对路径写法都有哪些( ) ./和../表示什么? 像这样的还有哪些?
*第一种:IO流中的相对路径,相对于当前项目(project)
*类加载器中的相对路径
*web前端中的相对路径
3.直接打印文件的对象名和调用getPath方法有什么不同?
//toString() getPath() 从结果看,这两个方法的返回值是一模一样的
推荐按照功能去用:
toString:需要查看file类的内部属性
getPath:需要查看构造方法的参数字符串表示形式
六、递归
1.概念
递归指的是方法定义中调用方法本身的现象
//递归是一种思想,出现在方法中
2.注意事项
递归一定要有出口。否则内存溢出 //死循环
递归虽然有出口,但是递归的次数也不宜过多。否则内存溢出
//System.out.println(f(200000000));
3.递归的方法格式
*递归一定要有出口 ---------- >在递归方法中,一定是有一个if判断语句的
*方法定义中调用方法本身的现象---------->要有方法调用自己本身
格式:
public 返回值 方法名(参数列表){
if(是否为出口){ //找到出口条件
return 值;
}else{
方法调用自己本身 //方法调用自己本身的规则
}
}
4.递归的好处
代码的方法复杂度较低
5.递归求阶乘的案例
5! = 5x4x3x2x1
4!=4x3x2x1
3!=3x2x1
2!=2x1
1!=1
出口条件:1!=1
自己调用自己本身的规律:5! = 5* 4!
代码实现:
public static int jc(int i){
if(i==1){ //找到出口条件
return 1;
}else{
return i*jc(i-1); //方法调用自己本身的规则
}
}
6.遍历目录案例
需求:找出文件夹下面所有的文件的名称
出口条件:如果找到的文件对象为文件(不是文件夹)
调用自己本身的规则:如果是文件夹的话,需要递归调用自己
代码实现:
public static void getAllPath(File file){
File[] files = file.listFiles();
for (File f1 : files){
if (f1.isFile()){ //出口条件:如果是文件对象,直接打印路径
System.out.println(f1.getAbsolutePath());
}else{
getAllPath(f1); //自己调用自己的规则,如果文件夹内部还是一个文件夹,那么调用自己本身
}
}
}
IO流
一、IO流的引入
File类的功能时可以创建、删除文件,还可以查看文件的相关属性,但是它无法查看文件的内部内容。如果说我想查看文件的内容,就要使用IO流
二、IO流的概述和分类
1.IO流的概念
I:in的意思,输入流
O:out的意思,输出流
流:在Java中华我们把数据的流向传输称为流
2.IO流的分类
(1)按照"数据"的流向 //站在代码的角度(内存)
*输入流:读数据
*输出流:写数据
(2)按照数据类型来分
*字节流
字节输入流
字节输出流
*字符流
字符输入流
字符输出流
//扩展:数据的两种状态
(1)游离态数据
运行在程序中(内存)的数据(特点:程序关闭之后,再次打开数据就没了) //学生管理系统
(2)持久化数据
存储在硬盘上的数据(特点:程序关闭之后,再次打开的时候数据还在)//视频
3.IO流的使用场景
如果操作的是纯文本文件(指的是用记事本打开能看懂的),优先使用字符流
如果操作的是图片、视频、音频等二进制文件。优先使用字节流
如果不确定文件类型,优先使用字节流。字节流是万能的流
三、字节流写数据
1.字节输出流的抽象根类
public abstract class OutputStream
//抽象类
2.具体子类
public class FileOutputStream
extends OutputStream
3.构造方法
FileOutputStream(String name) 创建文件输出流以指定的名称写入文件。
//参数name:代表的是要写入的文件的路径
//注意事项:
FileOutputStream fos = new FileOutputStream("day08/a.txt");
*如果a.txt不存在,那么执行上面这行代码就会默认帮我们去创建
*如果a.txt已经存在,那么会把该文件中的内容全部清空 //☆☆☆☆☆
4.写数据的方法
void write(int b) 将指定的字节写入此文件输出流。
//int类的参数b :需要的ASCII码
5.释放资源
void close() 关闭此文件输出流并释放与此流相关联的任何系统资源。
//为什么要释放资源?
int i = 10;
System.out.println(i);//因为i都是存在于内存中,那么在使用完不使用的时候,会被垃圾回收器回收
FileOutputStream fos = new FileOutputStream("day08/a.txt"); //a.txt是持久态的数据,而持久态数据是存在于硬盘上的,不会消失
//所以和a.txt关联的fos就不会被自动释放,所以只能手动释放
6.写数据的过程
*创建字节输出流的对象(其实是把管道搭建在目标文件上)
*调用写数据的方法
*释放资源
代码实现:
FileOutputStream fos = new FileOutputStream("day08/a.txt");
fos.write(97);
fos.close();
7.写数据的三种方式
(1)void write(int b) 将指定的字节写入此文件输出流。
(2)void write(byte[] b) 将 b.length字节从指定的字节数组写入此文件输出流。 //就是因为数组里面可以存放多个字节,一次性输出多个字节,提供效率
(3)void write(byte[] b, int off, int len) 将 len字节从指定的字节数组开始,从偏移量 off开始写入此文件输出流。//为了接下来赋复制文件做准备的
//补充方法
String--------- > 字节数组
例如:byte[] bytes = "xxx".getBytes();
四、字节流写数据的两个小问题
1.换行
windows:\r\n
// \r:这里的r是return的首字母,代表把光标移动到这一行的最前面
\n: 这里的n是newline首字母,表示将光标移动到下一行
linux:\n
mac:\r
//这里的换行针对的是系统自带的记事本
2.追加写入
FileOutputStream(String name, boolean append) 创建文件输出流以指定的名称写入文件。
//参数append 如果传入true,就代表追加写入,如果为false,代表不追加
五、finally关键字
*特点:finally代码块里面的程序一定会被执行,触发虚拟机退出
*应用场景:
//释放资源
*异常的结构
try{
可能出现异常的代码
}catch(异常名称 变量名){
处理异常的代码
}finally{
一般是释放资源
}
异常的多种方式:
(1)try--catch--finally //正确
(2)try---finally //正确
(3)catch--finally //错误
(4)try---catch---catch--finally //正确
//try必须有,而且只能出现一次, catch可以出现任意次 finally最多出现一次
六、字节流读数据
1.字节输入流的抽象根类
public abstract class InputStream
//抽象类,不能直接创建对象
2.具体子类
public class FileInputStream
extends InputStream
3.构造方法
FileInputStream(String name) 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。
//参数 name :指的是需要读的那个文件的抽象路径
4.读取数据的方法
int read() 从该输入流读取一个字节的数据。
//返回值 int :返回的是从文件中读取到的数据 如果返回值-1,表示文件读完了
5.循环读数据的步骤
(1)创建字节输入流对象
(2)循环读取数据
(3)释放资源
代码实现:
public class Demo2 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("day08/a.txt");
int len;
while ((len=fis.read())!=-1){
System.out.print((char) len);
}
fis.close();
}
}
6.字节流赋值文本文件案例
*复制"文件": File类来创建的 //a.txt
*复制"文件中的内容": IO来操作
代码实现:
public class Demo4 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("day08/a.txt");
FileOutputStream fos = new FileOutputStream(new File("day08/b.txt"));
int len;
while ((len=fis.read())!=-1){
fos.write(len);
}
fos.close();
fis.close();
}
}
7.字节流一次读一个字节数组相关方法
(1)int read() 从该输入流读取一个字节的数据
//返回值:int指的是从文件中读取到的数据 如果返回值为-1,表示读取结束
(2)int read(byte[] b) 从该输入流读取最多 b.length个字节的数据到一个字节数组。
//返回值 int指的是读取到的数据的长度 参数:byte[]这里面才是真正读取到的数据
//数组的长度一般是1024的倍数?
1K = 1024 byte
1M = 1024K
1G = 1024M
(3)int read(byte[] b, int off, int len) 从该输入流读取最多 len个字节的数据到字节数组。
// //返回值 int指的是读取到的数据的长度 参数:byte[]这里面才是真正读取到的数据 ,off指的是数组开始索引 len指的长度
//我怎么把读取到byte数组中的元素转换成String类型呢?
byte[] ----------- > String
例如:
String s = new String(bytes);
问题:为什么读数据的时候,最后转换成字符串的时候用的0-len
//因为如果最后一轮读取到的数据不是满数组,那么就可能多读了上一次的残留数据
8.字节流复制图片案例
public class CopyPic {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("C:\\Users\\chun\\Desktop\\1.jpg");
FileOutputStream fos = new FileOutputStream("day08/mn.jpg");
int len;
byte[] bytes = new byte[1024];
while ((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
fos.close();
fis.close();
}
}
//字节流小总结
1.字节输入流
*抽象根类:InputStream
具体子类:FileInputStream
*读数据的方法
(1)int read() 从该输入流读取一个字节的数据
(2)int read(byte[] b) 从该输入流读取最多 b.length个字节的数据到一个字节数组。
(3)int read(byte[] b, int off, int len) 从该输入流读取最多 len个字节的数据到字节数组。
2.字节输出流
*抽象根类:OutputStream
具体子类:FileOutputStream
*写数据的方法
(1)void write(int b) 将指定的字节写入此文件输出流。
(2)void write(byte[] b) 将 b.length字节从指定的字节数组写入此文件输出流。
(3)void write(byte[] b, int off, int len) 将 len字节从指定的字节数组开始,从偏移量 off开始写入此文件输出流。
3.复制文件的方式
(1)一次复制一个字节
(2)一次复制一个字节数组