File类
在java.io.File下,提供了文件本身的信息,删除文件,创建文件等
//创建file对象,指定文件路径
File f = new File("C:\\Users\\lucas的电脑\\Desktop\\封面图\\1.gif");
long size = f.length();//文件字节大小
System.out.println(size);
//2 file创建对象支持相对路径 和 绝对路径 是在工程下
//file对象代表文件夹 exists()判断这个路径是否存在
file一些常用api
File f = new File("C:\\Users\\lucas的电脑\\Desktop\\封面图\\1.gif");
//获取绝对路径
System.out.println(f.getAbsolutePath());
//获取定义的路径
System.out.println(f.getPath());
//获取文件名称
System.out.println(f.getName());
//获取文件字节大小
System.out.println(f.length());
//获取文件最后修改时间 毫秒值
long time = f.lastModified();
System.out.println(new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(time));
//判断是否是文件
System.out.println(f.isFile());//true
创建和删除文件或文件夹
File f = new File("bug\\src\\com\\hx\\file\\data.txt");
//创建文件
System.out.println(f.createNewFile());//几乎不用
//创建一级目录
File f2 = new File("bug\\src\\com\\hx\\text");
f2.mkdir();
//创建多级目录
File f3= new File("bug\\src\\com\\hx\\text\\aaa\\bbb\\ccc\\ddd");
f3.mkdirs();
//删除文件或空文件夹
f2.delete();
遍历文件
//定位一个目录
File f = new File("C:\\Users\\lucas的电脑\\Desktop\\封面图");
//获取当前目录下一级文件名称放在字符串数组中返回
String[] names = f.list();
for (String name : names) {
System.out.println(name);
}
//遍历一级文件对象 在对象数组中去返回
File[] f1 = f.listFiles();
for (File file : f1) {
System.out.println(file.getName());
}
listFiles只能拿到一级目录下的所有内容,再想拿到一级目录中的目录中文件拿不到,所有出现方法递归。
二,方法递归
方法直接调用自己或间接调用自己的形式称为方法递归。
直接递归
public static void main(String[] args) {
text();
}
public static void text(){
System.out.println("========text执行======");
text();//自己直接调用自己 直接递归
}
没有控制终止,会出现死循环,导致栈内存溢出
间接递归
间接调用自己出现死循环
public static void main(String[] args) {
text1();
}
public static void text(){
System.out.println("========text执行======");
text1();//自己直接调用自己 直接递归
}
public static void text1(){
System.out.println("========text执行======");
text();//自己直接调用自己 直接递归
}
如算5的阶乘 54321
public static void main(String[] args) {
int result = fn(5);
System.out.println(result);
}
public static int fn(int num){
if(num==1){
return 1;
}else {
return num* fn(num-1);
}
}
执行流程
递归算法理论
- 递归公式
- 递归终结点
- 递归方向必须走向终结点
非规律化递归
需求:从c盘中搜索某个文件名称并输出他的绝对路径
先定位,再遍历,如果是文件判断是不是想要的,是文件夹继续递归
public static void main(String[] args) {
searchFile(new File("D:/"),"制定学习.txt");
}
public static void searchFile(File dir,String name){
if(dir!=null&&dir.isDirectory()){
//可以寻找
File[] files = dir.listFiles();//null
//判断是否存在一级文件对象
if(files!=null&&files.length>0){
//开始遍历
for (File file : files) {
if(file.isFile()){
//说明是文件 判断是否需要
if (file.getName().equals(name)){
System.out.println(file.getAbsolutePath());
}
}else{
//继续遍历 也就开将上面的步骤开始递归
searchFile(file,name);
}
}
}
}else{
// 当前搜索的不是文件夹
System.out.println("您搜索的不是文件夹");
}
}
三,字符集
计算机底层不可以直接存储字符的,计算机底层只能存储二进制(0 1)
二进制可以转换十进制
所以计算机底层可以表示十进制编号,计算机可以给人类字符进行编号存储,如a=97 二进制(01100001)
ASCII字符集(美国信息交换标准代码)
包括了数字,英文,符号
使用一个字节存储一个字符,一个字节是8位
GBK编码格式
windows系统默认码表,兼容ASCII码表,包含了几万个汉字
gbk是中国的码表,一个中文以2个字节存储
Unicode码表
万国码,因为全世界每个国家都自己有一套编码不利于流通,所以搞了一套通用编码
最为常见的就是UTF-8,三个字节表示一个中文
字符集编码和解码的操作
//编码
String name = "abc呜呜呜";
byte[] arr = name.getBytes("utf-8"); //以当前代码默认字符集进行编码(utf-8)
System.out.println(Arrays.toString(arr));
System.out.println(arr.length);
//解码
String s = new String(arr,"utf-8");
System.out.println(s);
结果
因为utf-8汉字代表三个字节 所以3*3=9 外加3个英文
我们发现中文汉字都是负数,所以在utf-8编码中负数是汉字
编码和解码必须一致,否则乱码
四,IO流(输入输出流)
读写数据的
io流流程
io流分为
字节流适合读取一切内容(适合读文本)
字符流适合读取文本内容
字节输入流
1 每次只读一个字节
从硬盘读取到内存中
//输入流 从硬盘读到内存
InputStream is = new FileInputStream("D:\\code\\javasepro\\bug\\src\\data.txt");
//读取一个字节返回
int num = is.read();//没有可读的返回-1
System.out.println((char)num);//转换为char a
缺点:
- 1.性能慢
- 2.读中文乱码 (因为中文2个字节)
2 每次读取一个字节数组
//输入流 从硬盘读到内存
InputStream is = new FileInputStream("D:\\code\\javasepro\\bug\\src\\data.txt");
//定义一个数组,用于读取字节
byte[] buffer = new byte[3];
int b = is.read(buffer);//每次读取字节数
String s = new String(buffer,0,b);
System.out.println(s);
- 依然无法解决中文输出乱码问题
3 一次读取完文件全部字节
读取中文不乱码,需要定义一个与文件一样大的字节数组,一次性读取完文件全部字节
但这样有一个缺点,如果文件过大字节数组可能引起内存溢出.
//输入流 从硬盘读到内存
File file = new File("D:\\code\\javasepro\\bug\\src\\data.txt");
InputStream is = new FileInputStream(file);
//定义一个与字节数组与文件一样大
byte []buffer = new byte[(int) file.length()];
int len = is.read(buffer);
System.out.println(len);
System.out.println(file.length());
System.out.println(new String(buffer));
有一个api可以直接读取全部内容
readAllBytes
字节输出流
//创建一个输出流与目标文件相连
//会清空之前的数据 再写新数据
OutputStream os = new FileOutputStream("D:\\code\\javasepro\\bug\\src\\out.txt");
//向文件中写数据
os.write('a');
os.write(98);
//写中文 还得用桶装
byte[] buffer = "中文汉字".getBytes(StandardCharsets.UTF_8);//字符串转换为字节数组
os.write(buffer);
os.flush();//写数据必须刷新数据 不关闭流
os.close();//释放资源,包含刷新
追加数据
OutputStream os = new FileOutputStream("D:\\code\\javasepro\\bug\\src\\out.txt",true);
文件拷贝
try {
// 可以拷贝一切文件
InputStream fileInputStream = new FileInputStream("D:\\code\\javasepro\\bug\\src\\out.txt");
//创建输出流
FileOutputStream fileOutputStream = new FileOutputStream("D:\\newcopy.txt");
//定义字节数组转移数据
byte[] buffer = new byte[1024];
int len ;//记录每次读取字节数
while ((len=fileInputStream.read(buffer))!=-1){
fileOutputStream.write(buffer,0,len);
}
System.out.println("复制完成");
fileOutputStream.close();
fileInputStream.close();
}catch (Exception e){
e.printStackTrace();
}
最好使用 try-catch-finally提供的finally来进行释放内存,无论成功与否都需要释放内存
还有一种try-with-resource来进行释放
try(里面放资源){
}
catch(Exception e){
//
}
这样会自动调用释放资源
字符流
字符输入流
每次读取一个字符
不会出现中文乱码
将磁盘上的数据以字符形式读取到内存中
//先创建管道
Reader fileReader = new FileReader("D:\\code\\javasepro\\bug\\src\\data.txt");
//读取字符返回
int code = fileReader.read();
System.out.println((char)code);
性能很慢
一次读取一个字符数组
//先创建管道
Reader fileReader = new FileReader("D:\\code\\javasepro\\bug\\src\\data.txt");
char[] arr = new char[1024];
int data;
while((data=fileReader.read(arr))!=-1){
String rs = new String(arr,0,data);
System.out.println(rs);
}
字符输出流
Writer fileWriter = new FileWriter("D:\\code\\javasepro\\bug\\src\\data2.txt");//每次启动会清空
//写一个字符出去
fileWriter.write('是');
fileWriter.flush();
//写一个字符串
fileWriter.write("一个字符串");
//写一个字符数组
char[] arr = "南大街看".toCharArray();
fileWriter.write(arr);
//写字符串一部分
fileWriter.write("一个字符串",0,3 );
五,缓存流
自带缓冲区,可以提高原始字节流,字符流读写数据性能
之所以快,是因为开辟了一块内存空间,读写先在内存中
原理:将原始流进行包装成缓冲输入流,用缓冲输入流的管道(自带8kb缓冲池)
字节缓冲流
- 字节缓冲输入流
InputStream fileInputStream = new FileInputStream("D:\\code\\javasepro\\bug\\src\\out.txt");
// 将原始流包装成字节输入缓冲流
InputStream bis = new BufferedInputStream(fileInputStream);
//创建输出流
OutputStream fileOutputStream = new FileOutputStream("D:\\newcopy.txt");
// 将原始流包装成字节输出缓冲流
OutputStream bos = new BufferedOutputStream(fileOutputStream);
- 字节缓冲输出流
OutputStream bos = new BufferedOutputStream(fileOutputStream);
字符缓冲流
新增了按行读取的功能
- 字符缓冲输入流
try(
Reader f = new FileReader("D:\\code\\javasepro\\bug\\src\\data.txt");
BufferedReader br = new BufferedReader(f);
) {
String rs ;
while ((rs = br.readLine())!=null){
System.out.println(br);
}
}catch (Exception e){
e.printStackTrace();
}
- 字符缓冲输出流
Writer fw = new FileWriter("D:\\code\\javasepro\\bug\\src\\data2.txt");//每次启动会清空
BufferedWriter bw = new BufferedWriter(fw);
bw.newLine();//换行
六,转换流
之前我们使用字符流没有乱码是因为,输入和输出(读写)都是utf-8的编码,代码编码和文件编码
如你的代码是utf-8,但你要读别人gbk的文件。
字符输入转换流
提前文件的原始字节流,原始字节不会出现问题,然后把字节流以指定编码转换为字符输入流,这样就不会乱码
InputStream is = new FileInputStream("d:/dada.txt");
Reader rd = new inputStreamReader(is,"gbk");//以gbk编码转换为字符输入流
字符输出转换流
字符以指定编码获取字节后再使用字节输出流写出去
Writer wt = new OutputStreamWriter("字节流");
七,对象序列化
以内存为基准,把内存中的对象存储到磁盘文件中去,称为对象序列化
对象文件输出流(ObjectOutputStream)
把对象数据存储到文件中
//1 创建学生对象
Student s = new Student("侯旭",22,"篮球");
//2 对象序列化 使用对象字节输出流包装字节输出流
ObjectOutputStream OOS = new ObjectOutputStream(new FileOutputStream("D:\\code\\javasepro\\bug\\src\\2.txt"));
//3 直接调用序列方法写入
OOS.writeObject(s);
//4 释放资源
OOS.close();
但是在Student类中必须实现Serializable
接口,目的是对象要序列化必须实现序列化接口 要告诉java虚拟机以序列化保存文件
八,对象反序列化
以内存为基准,把存储到磁盘文件中的对象恢复到内存中的对象,称为对象反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\code\\javasepro\\bug\\src\\2.txt"));
Student s = (Student) ois.readObject();//提取出来时是object类,需要强转一下
System.out.println(s);
Student{name='侯旭', age=22, hobby='篮球'}
但是这样会暴露你的年龄,如果不想暴露就不参与序列化,在成员变量前加transient
,这样不参与序列化
最好在实体类中加序列号版本
private static final long serialVsersionUid = 1;
八,打印流
image.png打印流:可以更方便,高效的写数据到文件中,可以实现打印什么数据就是什么数据97就是97,而不是字符a
PrintStream ps = new PrintStream('写文件路径');//字节输出流
PrintWriter ps = new PrintStream('写文件路径');//字符输出流 打印数据无区别.只能写字符数据出去
ps.println(97);
ps.println(你好);
ps.println(97.256);
properties属性集对象
是一个map集合,比hashmap更好用
-
properties核心作用
1 代表的是一个属性文件,可以把自己对象中的键值对信息存入到一个属性文件中去
属性文件是以后缀.properties接尾的文件,里面内容是key=value,后续做系统配置信息的 -
properties结合io流存储方法
//使用properties把键值对信息存入到属性文件中
Properties properties = new Properties();
properties.setProperty("admin","123456");
properties.setProperty("user1","123456");
properties.setProperty("user2","abc");
properties.setProperty("user3","123456");
System.out.println(properties);
//保存到文件中 参数1 目标地址 参数2 保存心得
properties.store(new FileWriter("D:\\code\\javasepro\\bug\\src\\user.properties"),"this a bug");
- 读取 文件中键值对信息
Properties properties = new Properties();
System.out.println(properties);
//加载属性文件中的键值对到属性对象properties中
properties.load(new FileReader("D:\\code\\javasepro\\bug\\src\\user.properties"));
System.out.println(properties);
//根据键取数据
String psw = properties.getProperty("user1");
System.out.println(psw);// 123456
九,Commons IO 框架
由第三方提供的一种操控io的类库,可以提高io功能开发的效率,
核心类库FileUtils和IoUtils
首先去官网下载,然后将jar包放在lib文件夹中并且加到依赖库
网友评论