1.File类
创建对象
File f1 = new File("D:/resource/ab.txt");
File f2 = new File("D:\\resource\\abc.txt");
基础方法
创建与删除方法
1、public boolean createNewFile():创建一个新文件(文件内容为空),创建成功返回true
2、public boolean mkdir():用于创建文件夹,注意:只能创建一级文件夹
3、public boolean mkdirs():用于创建文件夹,注意:可以创建多级文件夹
4、public boolean delete():删除文件,或者空文件,注意:不能删除非空文件夹
public class FileTest3 {
public static void main(String[] args) throws Exception {
// 1、public boolean createNewFile():创建一个新文件(文件内容为空),创建成功返回true,反之。
File f1 = new File("D:/resource/itheima2.txt");
System.out.println(f1.createNewFile());
// 2、public boolean mkdir():用于创建文件夹,注意:只能创建一级文件夹
File f2 = new File("D:/resource/aaa");
System.out.println(f2.mkdir());
// 3、public boolean mkdirs():用于创建文件夹,注意:可以创建多级文件夹
File f3 = new File("D:/resource/bbb/ccc/ddd/eee/fff/ggg");
System.out.println(f3.mkdirs());
// 3、public boolean delete():删除文件,或者空文件,注意:不能删除非空文件夹。
System.out.println(f1.delete());
System.out.println(f2.delete());
File f4 = new File("D:/resource");
System.out.println(f4.delete());
}
}
遍历文件夹
递归
-
从形式上来说,方法调用自己的形式称之为递归。
-
递归的形式:有直接递归、间接递归,如下面的代码。
public class RecursionTest1 {
public static void main(String[] args) {
test1();
}
// 直接方法递归
public static void test1(){
System.out.println("----test1---");
test1(); // 直接方法递归
}
// 间接方法递归
public static void test2(){
System.out.println("---test2---");
test3();
}
public static void test3(){
test2(); // 间接递归
}
}
例子(求阶乘)
public class RecursionTest2 {
public static void main(String[] args) {
System.out.println("5的阶乘是:" + f(5));
}
//求n个数的阶乘
public static int f(int n){
// 终结点
if(n == 1){
return 1;
}else {
return f(n - 1) * n;
}
}
}
简单说就是层层调用。
可以使用递归算法实现文件搜索。如下:
public class RecursionTest3 {
public static void main(String[] args) throws Exception {
searchFile(new File("D:/") , "QQ.exe");
}
public static void searchFile(File dir, String fileName) throws Exception {
// 1、把非法的情况都拦截住
if(dir == null || !dir.exists() || dir.isFile()){
return; // 代表无法搜索
}
// 2、dir不是null,存在,一定是目录对象。
// 获取当前目录下的全部一级文件对象。
File[] files = dir.listFiles();
// 3、判断当前目录下是否存在一级文件对象,以及是否可以拿到一级文件对象。
if(files != null && files.length > 0){
// 4、遍历全部一级文件对象。
for (File f : files) {
// 5、判断文件是否是文件,还是文件夹
if(f.isFile()){
// 是文件,判断这个文件名是否是我们要找的
if(f.getName().contains(fileName)){
System.out.println("找到了:" + f.getAbsolutePath());
Runtime runtime = Runtime.getRuntime();
runtime.exec(f.getAbsolutePath());
}
}else {
// 是文件夹,继续重复这个过程(递归)
searchFile(f, fileName);
}
}
}
}
}
2.字符集
ASCII码表一个字符存储一个字节。
GBK两个字节存储一个汉字,兼容ASCII,同样一个字节存储一个字母。
如何分辨哪些字节属于汉字或字母?
-
如果是存储字母,采用1个字节来存储,一共8位,其中第1位是0
-
如果是存储汉字,采用2个字节来存储,一共16位,其中第1位是1
GBK规定,汉字的第一个字节的第一位一定是1。
Unicode字符集
全世界有很多种语言,全部统一成一种字符集。
一共设计了三种编码方案。分别是UTF-32、UTF-16、UTF-8; 其中比较常用的编码方案是UTF-8
UTF-8编码方案:英文字母、数字占1个字节兼容(ASCII编码)、汉字字符占3个字节
编码解码
编码:把字符串按照指定的字符集转换为字节数组
解码:把字节数组按照指定的字符集转换为字符串
public class Test {
public static void main(String[] args) throws Exception {
// 1、编码
String data = "a我b";
byte[] bytes = data.getBytes(); // 默认是按照平台字符集(UTF-8)进行编码的。
System.out.println(Arrays.toString(bytes));
// 按照指定字符集进行编码。
byte[] bytes1 = data.getBytes("GBK");
System.out.println(Arrays.toString(bytes1));
// 2、解码
String s1 = new String(bytes); // 按照平台默认编码(UTF-8)解码
System.out.println(s1);
String s2 = new String(bytes1, "GBK");
System.out.println(s2);
}
}
IO流(字节流)
功能: 数据读写
FileInputStream相关方法
读取一个字节数据
第一步:创建FileInputStream文件字节输入流管道,与源文件接通。
第二步:调用read()方法开始读取文件的字节数据。
第三步:调用close()方法释放资源
public class FileInputStreamTest1 {
public static void main(String[] args) throws Exception {
// 1、创建文件字节输入流管道,与源文件接通。
InputStream is = new FileInputStream(("file-io-app\\src\\itheima01.txt"));
// 2、开始读取文件的字节数据。
// public int read():每次读取一个字节返回,如果没有数据了,返回-1.
int b; // 用于记住读取的字节。
while ((b = is.read()) != -1){
System.out.print((char) b);
}
//3、流使用完毕之后,必须关闭!释放系统资源!
is.close();
}
}
读取多个字节
public class FileInputStreamTest2 {
public static void main(String[] args) throws Exception {
// 1、创建一个字节输入流对象代表字节输入流管道与源文件接通。
InputStream is = new FileInputStream("file-io-app\\src\\itheima02.txt");
// 2、开始读取文件中的字节数据:每次读取多个字节。
// public int read(byte b[]) throws IOException
// 每次读取多个字节到字节数组中去,返回读取的字节数量,读取完毕会返回-1.
// 3、使用循环改造。
byte[] buffer = new byte[3];
int len; // 记住每次读取了多少个字节。 abc 66
while ((len = is.read(buffer)) != -1){
// 注意:读取多少,倒出多少。
String rs = new String(buffer, 0 , len);
System.out.print(rs);
}
// 性能得到了明显的提升!!
// 这种方案也不能避免读取汉字输出乱码的问题!!
is.close(); // 关闭流
}
}
读取全部字节(读取过大内存溢出)
byte[] buffer = is.readAllBytes();
System.out.println(new String(buffer));
FileOutputStream
写字节
第一步:创建FileOutputStream文件字节输出流管道,与目标文件接通。
第二步:调用wirte()方法往文件中写数据
第三步:调用close()方法释放资源
public class FileOutputStreamTest4 {
public static void main(String[] args) throws Exception {
// 1、创建一个字节输出流管道与目标文件接通。
// 覆盖管道:覆盖之前的数据
// OutputStream os =
// new FileOutputStream("file-io-app/src/itheima04out.txt");
// 追加数据的管道
OutputStream os =
new FileOutputStream("file-io-app/src/itheima04out.txt", true);
// 2、开始写字节数据出去了
os.write(97); // 97就是一个字节,代表a
os.write('b'); // 'b'也是一个字节
// os.write('磊'); // [ooo] 默认只能写出去一个字节
byte[] bytes = "我爱你中国abc".getBytes();
os.write(bytes);
os.write(bytes, 0, 15);
// 换行符
os.write("\r\n".getBytes());
os.close(); // 关闭流
}
}
字节流复制文件
1.需要创建一个FileInputStream流与源文件接通,创建FileOutputStream与目标文件接通
2.然后创建一个数组,使用FileInputStream每次读取一个字节数组的数据,存如数组中
3.然后再使用FileOutputStream把字节数组中的有效元素,写入到目标文件中
public class CopyTest5 {
public static void main(String[] args) throws Exception {
// 需求:复制照片。
// 1、创建一个字节输入流管道与源文件接通
InputStream is = new FileInputStream("D:/resource/meinv.png");
// 2、创建一个字节输出流管道与目标文件接通。
OutputStream os = new FileOutputStream("C:/data/meinv.png");
// 3、创建一个字节数组,负责转移字节数据。
byte[] buffer = new byte[1024]; // 1KB.
// 4、从字节输入流中读取字节数据,写出去到字节输出流中。读多少写出去多少。
int len; // 记住每次读取了多少个字节。
while ((len = is.read(buffer)) != -1){
os.write(buffer, 0, len);
}
os.close();
is.close();
System.out.println("复制完成!!");
}
}
IO流资源释放
在JDK7版本以前,我们可以使用try...catch...finally语句来处理。
try{
有可能产生异常的代码
}catch(异常类 e){
处理异常的代码
}finally{
释放资源的代码
finally里面的代码有一个特点,不管异常是否发生,finally里面的代码都会执行。
}
在JDK7版本之后,我们可以使用try...catch语句来处理自动释放。
try(资源对象1; 资源对象2;){
使用资源的代码
}catch(异常类 e){
处理异常的代码
}
IO流(字符流)
FileReader
读取文件
第一步:创建FileReader对象与要读取的源文件接通
第二步:调用read()方法读取文件中的字符
第三步:调用close()方法关闭流
public class FileReaderTest1 {
public static void main(String[] args) {
try (
// 1、创建一个文件字符输入流管道与源文件接通
Reader fr = new FileReader("io-app2\\src\\itheima01.txt");
){
// 2、一个字符一个字符的读(性能较差)
// int c; // 记住每次读取的字符编号。
// while ((c = fr.read()) != -1){
// System.out.print((char) c);
// }
// 每次读取一个字符的形式,性能肯定是比较差的。
// 3、每次读取多个字符。(性能是比较不错的!)
char[] buffer = new char[3];
int len; // 记住每次读取了多少个字符。
while ((len = fr.read(buffer)) != -1){
// 读取多少倒出多少
System.out.print(new String(buffer, 0, len));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
FileWriter
写文件
第一步:创建FileWirter对象与要读取的目标文件接通
第二步:调用write(字符数据/字符数组/字符串)方法读取文件中的字符
第三步:调用close()方法关闭流
public class FileWriterTest2 {
public static void main(String[] args) {
try (
// 0、创建一个文件字符输出流管道与目标文件接通。
// 覆盖管道
// Writer fw = new FileWriter("io-app2/src/itheima02out.txt");
// 追加数据的管道
Writer fw = new FileWriter("io-app2/src/itheima02out.txt", true);
){
// 1、public void write(int c):写一个字符出去
fw.write('a');
fw.write(97);
//fw.write('磊'); // 写一个字符出去
fw.write("\r\n"); // 换行
// 2、public void write(String c)写一个字符串出去
fw.write("我爱你中国abc");
fw.write("\r\n");
// 3、public void write(String c ,int pos ,int len):写字符串的一部分出去
fw.write("我爱你中国abc", 0, 5);
fw.write("\r\n");
// 4、public void write(char[] buffer):写一个字符数组出去
char[] buffer = {'黑', '马', 'a', 'b', 'c'};
fw.write(buffer);
fw.write("\r\n");
// 5、public void write(char[] buffer ,int pos ,int len):写字符数组的一部分出去
fw.write(buffer, 0, 2);
fw.write("\r\n");
} catch (Exception e) {
e.printStackTrace();
}
}
}
FileWriter写完数据之后,必须刷新(flush方法)或者关闭,写出去的数据才能生效。
缓冲流
缓冲流的作用:可以对原始流进行包装,提高原始流读写数据的性能。
缓冲流的底层自己封装了一个长度为8KB(8129byte)的字节数组,但是缓冲流不能单独使用,它需要依赖于原始流。
使用时包装原始流就行。
缓冲流不一定能提高性能。
转换流
InputStreamReader,OutputStreamWriter,这两个流我们把它叫做转换流。它们可以将字节流转换为字符流,并且可以指定编码方案。
举例即可:
public class InputStreamReaderTest2 {
public static void main(String[] args) {
try (
// 1、得到文件的原始字节流(GBK的字节流形式)
InputStream is = new FileInputStream("io-app2/src/itheima06.txt");
// 2、把原始的字节输入流按照指定的字符集编码转换成字符输入流
Reader isr = new InputStreamReader(is, "GBK");
// 3、把字符输入流包装成缓冲字符输入流
BufferedReader br = new BufferedReader(isr);
){
String line;
while ((line = br.readLine()) != null){
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class OutputStreamWriterTest3 {
public static void main(String[] args) {
// 指定写出去的字符编码。
try (
// 1、创建一个文件字节输出流
OutputStream os = new FileOutputStream("io-app2/src/itheima07out.txt");
// 2、把原始的字节输出流,按照指定的字符集编码转换成字符输出转换流。
Writer osw = new OutputStreamWriter(os, "GBK");
// 3、把字符输出流包装成缓冲字符输出流
BufferedWriter bw = new BufferedWriter(osw);
){
bw.write("我是中国人abc");
bw.write("我爱你中国123");
} catch (Exception e) {
e.printStackTrace();
}
}
}
打印流
打印流有两个,一个是字节打印流PrintStream,一个是字符打印流PrintWriter
public class PrintTest1 {
public static void main(String[] args) {
try (
// 1、创建一个打印流管道
// PrintStream ps =
// new PrintStream("io-app2/src/itheima08.txt", Charset.forName("GBK"));
// PrintStream ps =
// new PrintStream("io-app2/src/itheima08.txt");
PrintWriter ps =
new PrintWriter(new FileOutputStream("io-app2/src/itheima08.txt", true));
){
ps.print(97); //文件中显示的就是:97
ps.print('a'); //文件中显示的就是:a
ps.println("我爱你中国abc"); //文件中显示的就是:我爱你中国abc
ps.println(true);//文件中显示的就是:true
ps.println(99.5);//文件中显示的就是99.5
ps.write(97); //文件中显示a,发现和前面println方法的区别了吗?
} catch (Exception e) {
e.printStackTrace();
}
}
}
数据流
也是一种包装流
DataInputStream
DataOutputStream
序列化流
序列化:意思就是把对象写到文件或者网络中去。(简单记:写对象)
反序列化:意思就是把对象从文件或者网络中读取出来。(简单记:读对象)
也是包装流
ObjectOutputStream
-
第一步:先准备一个User类,必须让其实现Serializable接口。
// 注意:对象如果需要序列化,必须实现序列化接口。
public class User implements Serializable {
private String loginName;
private String userName;
private int age;
// transient 这个成员变量将不参与序列化。
private transient String passWord;
public User() {
}
public User(String loginName, String userName, int age, String passWord) {
this.loginName = loginName;
this.userName = userName;
this.age = age;
this.passWord = passWord;
}
@Override
public String toString() {
return "User{" +
"loginName='" + loginName + '\'' +
", userName='" + userName + '\'' +
", age=" + age +
", passWord='" + passWord + '\'' +
'}';
}
}
-
第二步:再创建ObjectOutputStream流对象,调用writeObject方法对象到文件。
public class Test1ObjectOutputStream {
public static void main(String[] args) {
try (
// 2、创建一个对象字节输出流包装原始的字节 输出流。
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream("io-app2/src/itheima11out.txt"));
){
// 1、创建一个Java对象。
User u = new User("admin", "张三", 32, "666888xyz");
// 3、序列化对象到文件中去
oos.writeObject(u);
System.out.println("序列化对象成功!!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
此时文件中已有对象,想要查看则需要反序列化。
ObjectInputStream
public class Test2ObjectInputStream {
public static void main(String[] args) {
try (
// 1、创建一个对象字节输入流管道,包装 低级的字节输入流与源文件接通
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("io-app2/src/itheima11out.txt"));
){
User u = (User) ois.readObject();
System.out.println(u);
} catch (Exception e) {
e.printStackTrace();
}
}
}
IO框架
这个框架的名字叫commons-io:其本质是别人写好的一些字节码文件(class文件),打包成了一个jar包。只需要把jar包引入到我们的项目中,就可以直接用了。
一个jar包中提供的工具类叫FileUtils,它的部分功能如下。
引入jar包
1.在模块的目录下,新建一个lib文件夹
2.把jar包复制粘贴到lib文件夹下
3.选择lib下的jar包,右键点击Add As Library,然后就可以用了。
使用示例
public class CommonsIOTest1 {
public static void main(String[] args) throws Exception {
//1.复制文件
FileUtils.copyFile(new File("io-app2\\src\\itheima01.txt"), new File("io-app2/src/a.txt"));
//2.复制文件夹
FileUtils.copyDirectory(new File("D:\\resource\\私人珍藏"), new File("D:\\resource\\私人珍藏3"));
//3.删除文件夹
FileUtils.deleteDirectory(new File("D:\\resource\\私人珍藏3"));
// Java提供的原生的一行代码搞定很多事情
Files.copy(Path.of("io-app2\\src\\itheima01.txt"), Path.of("io-app2\\src\\b.txt"));
System.out.println(Files.readString(Path.of("io-app2\\src\\itheima01.txt")));
}
}