一、FILE
1.1 创建对象
注意:
- File 对象既可以代表文件、也可以代表文件夹。
- File 封装的对象仅仅是一个路径名,这个路径可以是存在的,也允许是不存在的。
//绝对路径--从盘符开始
File file = new File("D:\\sample\\a.txt");
//相对路径--不带盘符,默认直接到当前工程下的目录寻找文件
File file = new File("模块名\\a.txt");
//反斜杠写法
File file = new File("D:/sample/a.txt");
1.2 常用方法--判断文件类型、获取文件信息
1.3 常用方法--创建文件、删除文件
注意: delete 方法默认只能删除文件和空文件夹,删除后的文件不会进入回收站。
1.4 常用方法--遍历文件夹
二、IO流
- 字节输入流:以内存为基准,来自磁盘文件 / 网络中的数据以字节的形式读入到内存中去的流
- 字节输出流:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去的流。
- 字符输入流:以内存为基准,来自磁盘文件 / 网络中的数据以字符的形式读入到内存中去的流。
- 字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流。
2.1 前置知识--字符集
1. 标准 ASCLL 字符集
使用1 个字节存储一个字符,首尾是 0 ,总共可表示 128 个字符。
2. GBK (汉字内码扩展规范,国标)
- 汉字编码字符集,包含了 2 万多个汉字等字符, GBK 中一个中文字符编码成两个字节的形式存储。
- 注意: GBK兼容了 ASCII字符集。
3. Unicode 字符集(统一码,也叫万国码)
UTF-8是 Unicode 字符集的一种编码方案,采取可变长编码方案,共分四个长度区: 1 个字节, 2 个字节, 3 个字节, 4 个字节。
汉字占 3 个字节,英文、数字占 1 个字节
- ASCLL字符集:只有英文、数字、符号等,占一个字节。
- GBK字符集:汉字占两个字节,英文、数字占一个字节。
- UTF-8字符集:汉字占三个字节,英文、数字占一个字节。
注意:
- 解码和编码时使用的字符集必须一致,否则会出现乱码。
- 英文、数字一般不会乱码,因为很多字符集都兼容了ASCLL编码。
4. Java编码、解码
2.2 释放资源的方式
1. try-catch-finally
finally 代码区的特点:无论 try 中的程序是正常执行了,还是出现了异常,最后都一定会执行 finally 区,除非JVM 终止。
作用:一般用于在程序执行完成后进行资源的释放操作(专业级做法)。
import java.io.FileInputStream;
import java.io.IOException;
public class Main {
public static void main(String[] args){
FileInputStream is = null;
try {
is = new FileInputStream("module1\\src\\sing.txt");
byte[] buffer = new byte[3];
int len;
while((len = is.read(buffer)) != -1){
System.out.print(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try{
if(is != null) is.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
2. try-with-resource
JDK 7 开始提供了更简单的资源释放方案,资源使用完毕后,会自动调用其 close() 方法,完成对资源的释放!
注意:()中只能放置资源,资源即实现了AutoCloseable 接口的类。
import java.io.FileInputStream;
public class Main {
public static void main(String[] args){
try (
FileInputStream is = new FileInputStream("module1\\src\\sing.txt");
){
byte[] buffer = new byte[3];
int len;
while((len = is.read(buffer)) != -1){
System.out.print(new String(buffer, 0, len));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//手写资源
class Demo implements AutoCloseable{
@Override
public void close() throws Exception {
System.out.println("临界资源释放。。。");
}
}
public class Main {
public static void main(String[] args){
try (
Demo d = new Demo();
){
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出:
2.3 IO流--字节流
1. 字节输入流--FileInputStream
抽象类InputStream的一个实现类
1.1 每次读取一个字节
//代码示例
import java.io.FileInputStream;
public class Main {
public static void main(String[] args) throws Exception{
FileInputStream is = new FileInputStream("module1\\src\\sing.txt");
int b;
while((b = is.read()) != -1){
System.out.print((char) b);
}
is.close();
}
}
使用 FileInputStream 每次读取一个字节,读取性能较差,并且读取汉字输出会乱码。
1.2 每次读取多个字节
//代码示例
import java.io.FileInputStream;
public class Main {
public static void main(String[] args) throws Exception{
FileInputStream is = new FileInputStream("module1\\src\\sing.txt");
byte[] buffer = new byte[3];
int len;
while((len = is.read(buffer)) != -1){
System.out.print(new String(buffer,0,len));
}
is.close();
}
}
使用 FileInputStream 每次读取多个字节,读取性能得到了提升,但读取汉字输出还是会乱码。
1.3 一次读取完全部字节
//方式一
import java.io.File;
import java.io.FileInputStream;
public class Main {
public static void main(String[] args) throws Exception{
File file = new File("module1\\src\\sing.txt");
FileInputStream is = new FileInputStream(file);
byte[] buffer = new byte[(int) file.length()];
is.read(buffer);
//GBK为sing.txt文件编码的字符集
System.out.println(new String(buffer,"GBK"));
is.close();
}
}
//方式二
import java.io.File;
import java.io.FileInputStream;
public class Main {
public static void main(String[] args) throws Exception{
FileInputStream is = new FileInputStream("module1\\src\\sing.txt");
byte[] bytes = is.readAllBytes();
System.out.println(new String(bytes, "GBK"));
is.close();
}
}
可以解决字节流读取中文输出乱码的问题。
如果文件过大,创建的字节数组也会过大,可能引起内存溢出。
2. 字节输出流--FileOutputStream
抽象类OutputStream的一个实现类
//覆盖文件
import java.io.FileOutputStream;
public class Main {
public static void main(String[] args) throws Exception{
//覆盖文件
FileOutputStream os = new FileOutputStream("module1\\src\\test.txt");
os.write(76);
os.write(new byte[]{77,78,79});
os.write(new byte[]{77,78,79},1,2);
os.close();
}
}
//在文件后追加
import java.io.FileOutputStream;
public class Main {
public static void main(String[] args) throws Exception{
//在文件后追加
FileOutputStream os = new FileOutputStream("module1\\src\\test.txt",true);
os.write(76);
os.write(new byte[]{77,78,79});
os.write(new byte[]{77,78,79},1,2);
os.close();
}
}
2.4 IO流--字符流
字节流适合复制文件,不适合读写文本。
字符流适合读写文本。
1. 字符输入流--FileReader
抽象类Reader的一个实现类
import java.io.FileReader;
public class Main {
public static void main(String[] args){
try (
FileReader fr = new FileReader("module1\\src\\sing.txt");
){
int c;
while((c = fr.read()) != -1){
System.out.print((char) c);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2. 字符输出流--FileWriter
抽象类Writer的一个实现类
import java.io.FileWriter;
public class Main {
public static void main(String[] args){
try (
FileWriter fr = new FileWriter("module1\\src\\test.txt");
){
fr.write('你');
fr.write('好');
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意:字符输出流写出数据后,必须刷新流,或者关闭流,写出去的数据才能生效
2.5 IO流--缓冲流
1. 引入
缓冲流是对原始流进行包装,以提高原始流读写数据的性能。
作用:提高字节/符流读写数据的性能。
原理:字节/符缓冲流自带了 8KB 缓冲池
以字符缓冲输入流为例:在内存中申请了8KB的缓冲池。每次从数据源(外存)中一次性读入8KB的数据,之后原始流再在缓冲池读入数据(内存->内存),减少了系统调用 的次数,提高性能。
2. 字节缓冲流
3. 字符缓冲流
3.1 字符缓冲输入流--BufferedReader
import java.io.BufferedReader;
import java.io.FileReader;
public class Main {
public static void main(String[] args){
try (
BufferedReader br = new BufferedReader(new FileReader("module1\\src\\sing.txt"));
){
String str;
while((str = br.readLine()) != null){
System.out.println(str);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.2 字符缓冲输出流--BufferedWriter
2.6 IO流--转换流
1. 引入
不同编码读取出现乱码问题:
- 如果代码编码和被读取的文本文件的编码是一致的,使用字符流读取文本文件时不会出现乱码!
- 如果代码编码和被读取的文本文件的编码是不一致的,使用字符流读取文本文件时就会出现乱码!
2. 字符输入转换流--InputStreamReader
抽象类Reader的一个实现类
解决思路:先获取文件的原始字节流,再将其按真实的字符集编码转成字符输入流,这样字符输入流中的字符就不乱码了。
import java.io.FileInputStream;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args){
try (
//test.txt按GBK编码
FileInputStream is = new FileInputStream("module1\\src\\test.txt");
InputStreamReader isr = new InputStreamReader(is,"GBK");
){
int c;
while((c = isr.read()) != -1){
System.out.print((char) c);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2. 字符输出转换流--OutputStreamWriter
抽象类Writer的一个实现类
可以控制写出去的字符使用什么字符集编码。
解决思路:获取字节输出流,再按照指定的字符集编码将其转换成字符输出流,以后写出去的字符就会用该字符集编码了。
import java.io.*;
public class Main {
public static void main(String[] args){
try (
FileOutputStream os = new FileOutputStream("module1\\src\\test.txt");
OutputStreamWriter osw = new OutputStreamWriter(os,"GBK");
){
osw.write('你');
osw.write(97);
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.7 IO流--打印流
作用:打印流可以实现更方便、更高效的打印数据出去,能实现打印啥出去就是啥出去。
1. 字节输出打印流--PrintStream
1. 字符输出打印流--PrintWriter
PrintStream 和 PrintWriter 的区别 :
- 打印数据的功能上是一模一样的:都是使用方便,性能高效(核心优势)
- PrintStream 继承自字节输出流 OutputStream ,因此支持写字节数据的方法。
- PrintWriter 继承自字符输出流 Writer ,因此支持写字符数据出去。
//因为功能是相同的,所以代码只展示一个
import java.io.PrintStream;
public class Main {
public static void main(String[] args){
try (
PrintStream ps = new PrintStream("module1\\src\\test.txt");
){
ps.println(123);
ps.println("你好");
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.8 IO流--数据流
1. 数据输出流--DataOutputStream
抽象类OutputStream的一个实现类
允许把数据和其类型一并写出去
import java.io.DataOutputStream;
import java.io.FileOutputStream;
public class Main {
public static void main(String[] args){
try (
DataOutputStream dos = new DataOutputStream(new FileOutputStream("module1\\src\\test.txt"));
){
dos.writeByte(97);
dos.writeInt(123);
dos.writeBoolean(true);
dos.writeUTF("Hello World");
} catch (Exception e) {
e.printStackTrace();
}
}
}
2. 数据输入流--DataInputStream
抽象类InputStream的一个实现类
用于读取数据输出流写出去的数据
数据输出流写出的数据:
需要用数据输入流来解析
import java.io.DataInputStream;
import java.io.FileInputStream;
public class Main {
public static void main(String[] args){
try (
DataInputStream dis = new DataInputStream(new FileInputStream("module1\\src\\test.txt"));
){
System.out.println(dis.readByte());
System.out.println(dis.readInt());
System.out.println(dis.readBoolean());
System.out.println(dis.readUTF());
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意:读取数据的顺序应和写入的数据保持一致
2.9 IO流--序列化流
1. 对象字节输出流--ObjectOutputStream
可以把 Java 对象进行序列化:把 Java 对象存入到文件中去。
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class Main {
public static void main(String[] args){
try (
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("module1\\src\\test.txt"));
){
oos.writeObject(new Student("张三","男",18,96));
oos.writeObject(new Student("李四","男",20,86));
oos.writeObject(new Student("王五","男",20,72));
System.out.println("序列化成功...");
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意:对象如果要参与序列化,必须实现序列化接口
import.io.Serializable
注意:如果某个成员变量不想参与序列化,在前加transient关键字
2. 对象字节输入流--ObjectInputStream
可以把 Java 对象进行反序列化:把存储在文件中的 Java 对象读入到内存中来。