File类概述
File类在包 java.io.File下,代表操作系统的文件对象(文件、文件夹)
File类提供了诸如:定位文件获取文件本身信息,删除文件,创建文件(文件夹)等功能
File类创建对象
//构造方法
File (String pathname )
File (File parent, String child)
File(File parent String , String child)
创建File对象(指定文件的路径)
路径写法:
- D:\study\xuesheng.jpeg
- D:/study/xuesheng.jpeg
创建File对象(支持绝对路经,支持相对路径(重点))
绝对路经:从盘符开始,依赖当前系统
相对路经:一般定位于模块中的文件的,定位到工程下
File f = new File(“file-io-app.src.data.txt”);
File 创建对象(可以是文件也可以是文件夹)
file常用API
判断文件类型,获取文件信息
File f = new File (“D:\\study\\xuesheng.jpeg”);
long time = f.lastModified();
System.out.println(“最后的修改时间是”+new SimpleDateFormat(“yyyy/MM/did HH:mm:ss”).format(time));
创建文件,删除文件功能
删除文件,占用也可以删除
遍历文件夹
//1. 定位一个目录
File f = new File ("D:/study");
String [] names = f.list();
for(String name:names){
System.out.println("name");
}
//2.只能遍历 一级文件对象
File files = f.listFiles();
for(File file:files){
System.out.println("file.getAbsolutePath()");
}
//3.listFiles 注意事项:
//当调用者不存在时,返回null
//当调用者是一个文件时,返回null
//当调用着是一个空文件夹时,返回一个长度为0的数组
//当调用者是一个有内容的文件夹时,将文件和文件夹的路径放在File数组中
//当调用者是一个有隐藏文件的文件夹时,将里面所有的文件和文件夹的路径放在File数组中返回,包含隐藏内容
方法递归(文件搜索)
递归的形式和特点
方法递归:方法直接调用自己或者间接调用自己的形式称为方法递归
直接递归:方法自己调用自己
间接递归:方法调用其他方法,其他方法又回调方法自己
递归的算法流程,核心要素
导学-计算1-n的阶乘
公式为f(n) = f(n-1)*n;
非规律化递归案例-文件搜索
需求:文件搜索,从C盘中,搜索出某个文件名称并输出绝对路径
分析:
- 先定位出的应该是一级文件对象
- 遍历所有一级文件对象,判断是否为文件
- 如果是文件,判断是否为自己想要
- 如果是文件夹,需要继续递归进去重复上述过程
import java.io.File;
public class RecursionDemo {
public static void main(String[] args) {
//2. 传入目录 和 文件名称
File file = new File("D:/");
searchFile(file,"dhdgffkkebhmkfjojejmpbldmpobfkfo");
}
/**
*1. 搜索某个目录下的全部文件,找到我们想要的
* @param dir 被搜索的源目录
* @param fileName 被搜索的文件名称
*/
public static void searchFile(File dir,String fileName){
//3. 判断dir是否为目录
if(dir!=null && dir.isDirectory()){
//可以找了
//4. 提取当前目录下的以及文件对象
File files[] = dir.listFiles();
//5. 判断是否存在一级文件对象,存在在遍历
if(files !=null&&files.length!=0){
for (File file :files){
//6. 判断当前的一级文件对象是文件还是目录
if(file.isFile()){
//7. 是不是我们要找的
if(file.getName().contains((fileName))){
System.out.println("找到了"+file.getAbsoluteFile());
}
//8. 是文件夹
}else {
searchFile(file,fileName);
}
}
}
}else{
System.out.println("对不起当前搜索的位置不是文件夹");
}
}
}
字符集
常见字符集介绍
基础知识
- 计算机底层不能直接存储字符的,计算机中底层只能存储二进制(0,1)
- 二进制是可以转换为十进制的
- 计算机底层是可以表示十进制编号。计算机可以给文类字符进行编号存储,这套编号规则就是字符集
ASCII字符集
GBK
Unicode码表(统一码,万国码):由于Unicode会先通过UTF-8的编码称二进制后再存储到计算机
字符串常见的字符组成:
英文和数字等在任何国家的字符集中都占一个字节
GBK字符中一个英文字符占2个字节
UTF-8编码中一个中文一般占三个字节
编码前的字符集和编码好的字符集必须一致,否则会出现中文符乱码
字符集的编码,解码操作
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
//1. 编码:把文字转换为字节(使用指定编码)
String name = "abc我爱你中国";
byte[] bytes = new byte[0];//以当前代码默认字符集进行编码(UTF-8)
// bytes = name.getBytes();
try {
bytes = name.getBytes("GBK");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
System.out.println(bytes.length);
System.out.println(Arrays.toString(bytes));
//2. 解码:把字节转换成对应的中文形式(编码前和编码后的字符集必须一致,否则乱码)
String rs = null;//默认UTF-8
try {
rs = new String(bytes,"GBK");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
System.out.println(rs);
}
}
IO流概述
分类
按流的方向分
IO流也称为输入,输出流,就是用来读写数据的
I表示input,是从数据从硬盘文件读入到内存的过程,称之输入,负责读
O表示output,是内存程序的数据从内存写出到硬盘文件的过程,称之为输出,负责写
按流中的数据最小单位分
字节流
字符流
组合
流 | 概念 | 抽象类 |
---|---|---|
字节输入流 | 以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流 | InputStream |
字节输出流 | 以内存为基准,把来自内存中的数据以字节写出到磁盘文件/网络中去的流 | OutputStream |
字符输入流 | 以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中去的流 | Reader |
字符输出流 | 以内存为基准,把来自内存中的数据以字符写出到磁盘文件/网络中去的流 | Writer |
字节流的使用
字节流适合做一切文件数据的拷贝,任何文件底层都是字节,拷贝是一字不漏地转移字节,只要前后的文件格式,编码一致没有任何问题。
字节输入流:每次读取一个字节
输出结果
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class FileInputSream {
public static void main(String[] args) {
try {
//1. 创建一个文件字节输出流管道与源文件接通
//InputStream is = new FileInputStream(new File("SuanFa\\logback-APP\\srd\\data"));
//简写
InputStream is = new FileInputStream("logback-APP\\src\\data");
// //读取一个字符并返回
// int bi = is.read();
// System.out.println((char) bi);
int b ;
while ((b = is.read())!=-1){
System.out.print((char) b);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
每次读取一个字节存在的问题
性能比较慢
读取中文字符输出无法避免乱码问题
字节输入流:每次读取一个字节数组
import java.io.FileInputStream;
import java.io.InputStream;
public class FileInputSream_Demo02 {
/**
*目标:使用文件字节输入流每次读取一个字节数组的数据
*/
public static void main(String[] args) throws Exception{
//1. 创建一个文件字节输入流管道与源文件接通
InputStream is = new FileInputStream("logback-APP\\src\\data");
// //2. 定义一个字节数组,用于读取字节数组
// byte[] buffer = new byte[3];
// int len1 = is.read(buffer);
// System.out.println("读取了几个字节"+len1);
// String rs1 = new String(buffer);
// System.out.println(rs1);
//
// int len2 = is.read(buffer);
// System.out.println("读取了几个字节"+len2);
// String rs2 = new String(buffer);
// System.out.println(rs2);
//
// int len3 = is.read(buffer);
// System.out.println("读取了几个字节"+len3);
// //读取多少,倒出多少
// String rs3 = new String(buffer,0,len3);
// System.out.println(rs3);
//
//使用循环
byte[] buffer = new byte[3];
int len ;
while((len=is.read(buffer))!=-1){
//读取多少,倒出多少
System.out.print(new String(buffer,0,len));
}
}
}
每次读取一个字节数组存在的问题
性能得到了提升
读取中文字符输出无法避免乱码问题
字节输入流:一次读完全部字节
如何使用字节输入流读取中文内容输出不出现乱码
定义一个与文件一样大的字节数组,一次性读取完文件的全部字节
直接把文件数据读取到一个字节数组可以避免乱码存在的问题、
如果文件过大,字节数组可能引起内存溢出
方式一:自己·定义一个与文件大小一样大,然后使用读取字节数组的方法,一次性读取完成
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class FileInputSream_Demo03 {
/**
*目标:使用文件字节输入流一次读取文件中的所有数据,可以解决中文乱码问题
*/
public static void main(String[] args) throws Exception{
//1. 创建一个文件字节输入流管道与源文件接通
File f = new File("logback-APP\\src\\data");
InputStream is = new FileInputStream(f);
//2.定义一个字节数组与文件的大小一样大
byte [] buffer = new byte[(int)f.length()];
int len = is.read(buffer);
System.out.println("读取了多少字节"+len);
System.out.println("文件大小"+f.length());
System.out.println(new String(buffer));
}
}
方法二:官方为字节输入流InputStream提供了如下API可以将字节把文件全部数据提取到一个字节数组中
bytes [] buffer = is.readAllBytes();
字节输出流:写字节数据到文件
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
public class FileOutputSream_Demo01 {
public static void main(String[] args) throws Exception{
//1. 创建一个文件字节输出流管道与目标文件接通
OutputStream os = new FileOutputStream("logback-APP\\\\src\\\\data",true);
// OutputStream os = new FileOutputStream("logback-APP\\\\src\\\\data");//先清空之前的数据,写新的数据
//2. 写数据出去
//a. public void write(int a):写一个字节出去
os.write('a');
os.write(98);
// os.write('徐');
os.write("\r\n".getBytes(StandardCharsets.UTF_8));//如果只有\n在windows系统中会是换行符,但是在linux系统中将不能识别,\r\n在很多系统中均适用
//b. public void write(byte[] buffer):写一个字节数组出去
byte [] buffer = {'a',97,98,99};
os.write(buffer);
os.write("\r\n".getBytes(StandardCharsets.UTF_8));
byte [] buffer2 = "我是中国人".getBytes(StandardCharsets.UTF_8);
os.write(buffer2);
os.write("\r\n".getBytes(StandardCharsets.UTF_8));
//c. public void write(byte[] buffer):写一个字节数组的一部分出去
byte [] buffer3 = {'a',97,98,99};
os.write(buffer3,0,3);
os.write("\r\n".getBytes(StandardCharsets.UTF_8));
os.flush(); //写数据一定要刷新数据
os.close();//释放资源,包含了刷新的!关闭后流不可以再用
}
}
资源释放的方式
try-catch-finally
finally:在处理异常时提供finally块来执行所有清除操作
特点:被finally控制的语句最终一定会执行,除非JVM退出(System.exit();)
作用:finally代码块是最终一定要执行的,可以在代码执行完毕的最后用于释放资源
//格式
try{
}catch(Exception e){
}finally{
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
public class FileOutputSream_Demo01 {
public static void main(String[] args) {
OutputStream os = null;
try {
//1. 创建一个文件字节输出流管道与目标文件接通
os = new FileOutputStream("logback-APP\\\\src\\\\data",true);
// OutputStream os = new FileOutputStream("logback-APP\\\\src\\\\data");//先清空之前的数据,写新的数据
//2. 写数据出去
//a. public void write(int a):写一个字节出去
os.write('a');
os.write(98);
// os.write('徐');
os.write("\r\n".getBytes(StandardCharsets.UTF_8));//如果只有\n在windows系统中会是换行符,但是在linux系统中将不能识别,\r\n在很多系统中均适用
os.flush(); //写数据一定要刷新数据
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(os!=null)os.close();//释放资源,包含了刷新的!关闭后流不可以再用
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
try-with-resource
try(定义流对象){
可能出现异常的代码
}catch(异常类名 变量名){
异常处理代码
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
public class FileOutputSream_Demo01 {
public static void main(String[] args) {
try (
//这儿里面只能放置资源对象,用完会自动关闭
//自动调用资源对象的close方法关闭资源(即使出现异常也会做关闭操作)
//1. 创建一个文件字节输出流管道与目标文件接通
OutputStream os = new FileOutputStream("logback-APP\\\\src\\\\data",true);
// OutputStream os = new FileOutputStream("logback-APP\\\\src\\\\data");//先清空之前的数据,写新的数据
){
//2. 写数据出去
//a. public void write(int a):写一个字节出去
os.write('a');
os.write(98);
// os.write('徐');
os.write("\r\n".getBytes(StandardCharsets.UTF_8));//如果只有\n在windows系统中会是换行符,但是在linux系统中将不能识别,\r\n在很多系统中均适用
os.flush(); //写数据一定要刷新数据
} catch (IOException e) {
e.printStackTrace();
}
}
}
JDK7和JDK9中的()中只能 放置资源对象,否则报错;这里的资源就是实现了Closeable/AutoCloseable接口的类对象
字符流的使用
字节流读取中文输出会存在问题:会乱码或内存溢出
文件字符输入流:一次读取一份字符
import java.io.FileReader;
import java.io.Reader;
public class FileReaderDemo01 {
//目标:每次读取一个字符
public static void main(String[] args) throws Exception {
//1. 创建一个字符输入流管道于与源文件接通
Reader fr = new FileReader("logback-APP\\src\\data");
//2. 读取一个字符
// int code = fr.read();
// System.out.println(code);
//
//3. 使用循环读取字符
int code ;
while ((code=fr.read())!=-1){
System.out.print((char)code);
}
}
}
字节流的好处:读取中文字符不会出现乱码(如果代码和文件编码一致)
每次读取一个字符会存在的问题:性能较慢
文件字符输入流:一次读取一个字符数组
import java.io.FileReader;
import java.io.Reader;
public class FileReaderDemo02 {
//目标:每次读取一个字符
public static void main(String[] args) throws Exception {
//1. 创建一个字符输入流管道于与源文件接通
Reader fr = new FileReader("logback-APP\\src\\data");
//2. 用循环每次读取一个字符数组
char [ ] buffer = new char[1024];
int len;
while ((len = fr.read(buffer))!=-1){
String rs = new String(buffer,0,len);
System.out.print(rs);
}
}
}
每次读取一个字符数组的优势:性能较好
文件字符输出流
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class FileWriterDemo {
public static void main(String[] args) throws Exception {
//1. 创建一个字符输出流管道与原文件接通
// Writer fw = new FileWriter("logback-APP\\src\\data");//每次写进去,都会先清空
Writer fw = new FileWriter("logback-APP\\src\\data",true);
//a. public void write(int c):写一个字符出去
fw.write(98);
fw.write('s');
fw.write('徐');
fw.write("\r\n");
fw.write("abc 我是个中国人");
fw.write("\r\n");
//c. public void write(char[] buffer):写一个字符数组出去
fw.write("abc我是中国人".toCharArray());
fw.write("\r\n");
//d. public void write(String c,int len):写一个字符串的一部分出去
fw.write("abc我是中国人",0,4);
fw.write("\r\n");
//e. public void write(char[] buffer,int len):写一个1字符数组的一部分出去
fw.write("abc我是中国人".toCharArray(),0,4);
fw.write("\r\n");
fw.flush();
fw.close();
}
}
字节流,字符流总结
字节流,字符流如何选择使用:
- 字节流适合做一切文本数据的拷贝
- 字节流不适合读取中文输出
- 字符流适合作、做文本文件的操作(读,写·)