Java文件与IO流
File类
- java.io.File 类是文件和目录,路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作
- File可以表示目录,也可以表示文件
构造方法
方法名 | 作用 |
---|---|
public File(String pathname) | 通过给定的路径名,字符串转换为抽象路径名来创建新的 File实例 |
public File(String parent, String child) | 从父路径名字符串和子路径名字符串创建新的 File实例,根据父路径加子路径的意思 |
public File(File parent, String child) | 从父抽象路径名和子路径名字符串创建新的 File实例 |
public class Demo {
public static void main(String[] args) {
File file = new File("F:/IdeaProjectTwo/IT6666-Web/vue.config.js");
System.out.println(file);
File fileTwo = new File("F:/IdeaProjectTwo/IT6666-Web", "/vue.config.js");
System.out.println(fileTwo);
File fileThree = new File(file, "/a.txt");
System.out.println(fileThree);
}
}
🐤注意事项
- 一个 File 对象代表硬盘中实际存在的一个文件或者目录
- 无论该路径下是否存在文件或者目录,都不影响 File 对象的创建
File类常用方法
方法名 | 作用 |
---|---|
public String getAbsolutePath() | 返回此 File 的绝对路径名字符串,返回绝对路径 |
public String getPath() | 将此 File 转换为路径名字符串获取路径 |
public String getName() | 返回由此 File 表示的文件或目录的名称 |
public long length() | 返回由此 File 表示的文件的长度 |
public class Demo {
public static void main(String[] args) {
File file = new File("F:/IdeaProjectTwo/IT6666-Web/vue.config.js");
System.out.println(file.getAbsolutePath());
File fileTwo = new File("F:/IdeaProjectTwo/IT6666-Web", "/vue.config.js");
System.out.println(fileTwo.getPath());
File fileThree = new File(file, "/a.txt");
System.out.println(fileThree.getName());
System.out.println(file.length());
}
}
绝对路径和相对路径
- 绝对路径:从盘符开始的路径,这是一个完整的路径
- 相对路径:相对于项目目录的路径,不是从盘符开始,从
项目名称
的位置开始,不带项目名称
public class Demo {
public static void main(String[] args) {
File file = new File("F:/IdeaProjectTwo/IT6666-Web/vue.config.js");
System.out.println(file);
File fileTwo = new File("src/a.text");
System.out.println(fileTwo);
}
}
判断相关方法
方法名 | 作用 |
---|---|
public boolean exists() | 用于判断此 File 表示的文件或目录是否实际存在 |
public boolean isDirectory() | 此 File 表示的是否为目录 |
public boolean isFile() | 此 File 表示的是否为文件 |
public class Demo {
public static void main(String[] args) {
File file = new File("F:/IdeaProjectTwo/IT6666-Web/vue.config.js");
System.out.println(file.exists());
System.out.println(file.isDirectory());
System.out.println(file.isFile());
File fileTwo = new File("F:/IdeaProjectTwo/IT6666-Web");
System.out.println(fileTwo.exists());
System.out.println(fileTwo.isDirectory());
System.out.println(fileTwo.isFile());
}
}
创建删除相关方法
方法名 | 作用 |
---|---|
public boolean createNewFile() | 当且仅当具有该名称的文件尚不存在时,创建一个新的空文件 |
public boolean delete() | 删除由此 File 表示的文件或目录 |
public boolean mkdir() | 创建由此 File 表示的目录 |
public boolean mkdirs() | 创建由此 File 表示的目录,包括任何必需但不存在的父目录 |
public class Demo {
public static void main(String[] args) throws Exception {
File file = new File("BNTang.txt");
System.out.println(file.exists());
System.out.println(file.createNewFile());
System.out.println(file.exists());
File fileTwo = new File("newDir");
System.out.println(fileTwo.exists());
System.out.println(fileTwo.mkdir());
System.out.println(fileTwo.exists());
File fileThree = new File("newDira\\newDirb");
System.out.println(fileThree.mkdir());
System.out.println(fileThree.mkdirs());
System.out.println(file.delete());
System.out.println(fileTwo.delete());
System.out.println(fileThree.delete());
}
}
目录遍历
方法名 | 作用 |
---|---|
public String[] list() | 返回一个 String数组,表示该 File 目录中的所有子文件或目录 |
public File[] listFiles() | 返回一个 File 数组,表示该 File 目录中的所有的子文件或目录 |
public class Demo {
public static void main(String[] args) throws Exception {
File dir = new File("F:\\upload");
String[] names = dir.list();
for (String name : names) {
System.out.println(name);
}
File[] files = dir.listFiles();
for (File file : files) {
System.out.println(file);
}
}
}
🐤注意事项
- 调用 listFiles 方法的 File 对象,表示的必须是实际存在的目录,否则返回null,无法进行遍历
递归
- 指在当前方法内调用自己的这种现象
- 调用时,要有一个退出的条件,否则会死循环,一直调用
- 就是一种方法的调用,方法自己调用自己,如果没有出口的话,就变成了死循环了
public class Demo {
static int num = 10;
public static void main(String[] args) throws Exception {
System.out.println("main");
num--;
if (num == 0) return;
main(args);
}
}
🐤计算1 - n的和
public class Demo {
public static void main(String[] args) throws Exception {
int sum = getSum(3);
System.out.println(sum);
}
/**
* 传入一个数返回1到这个数的和
* @param num n
* @return 1 - n的结果
*/
private static int getSum(int num) {
if (num == 1){
return 1;
}
return num + getSum(num-1);
}
}
🦄文件搜索
- 搜索指定目录下指定扩展名的文件
- 例如:D盘下 aaa目录中所有的 .txt文件
public class Demo {
public static void main(String[] args) throws Exception {
printDir(new File("F:\\IdeaProjectTwo\\IT6666-Web"));
}
public static void printDir(File dir) {
File[] files = dir.listFiles();
for (File file : files) {
if (file.isFile()) {
if (file.getName().endsWith(".txt")) {
System.out.println("文件名:" + file.getAbsolutePath());
}
} else {
printDir(file);
}
}
}
}
🐸多级目录树形结构显示
public class Demo {
public static void main(String[] args) throws Exception {
printDir(new File("F:\\upload"), 0);
}
public static void printDir(File dir, int level) {
if (level != 0) {
printSpace(level);
for (int i = 0; i < level; i++) {
if (i == 0) {
System.out.print("|-");
} else {
System.out.print("-");
}
}
}
File[] files = dir.listFiles();
for (File file : files) {
if (file.isFile()) {
if (file.getName().endsWith(".txt")) {
System.out.println("文件名:" + file.getAbsolutePath());
}
} else {
printDir(file, level + 1);
}
}
}
private static void printSpace(int level) {
StringBuilder str = new StringBuilder();
for (int i = 0; i < level; i++) {
str.append(" ");
}
System.out.print(str);
}
}
🐤递归求阶乘
public class Demo {
public static void main(String[] args) throws Exception {
int num = getJieCheng(4);
System.out.println(num);
}
private static int getJieCheng(int num) {
if (num == 1) {
return 1;
}
return num * getJieCheng(num - 1);
}
}
🐤斐波那契数列
- 斐波那契数列:又称黄金分割数列、因数学家列昂纳多 • 斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为
兔子数列
- 指的是这样一个数列:1、1、2、3、5、8、13、21、34、…
- 求数列的第6位的值是多少
递归分析
- 当位数为1和2时,当前返回的值应该是1
- 当位数为3时,返回值应该是2=1+1
- 当位数为4时,返回值是3=2+1
- 当位数为5时,返回值是5=3+2
- 大于等于3的情况下,当前位数(n)的数值是 f(n - 1) + f(n - 2)
public class Demo {
public static void main(String[] args) {
int f = f(3);
System.out.println(f);
for (int i = 1; i <= 15; i++) {
System.out.print(f(i) + "\t");
}
}
public static int f(int n) {
if (n == 1 || n == 2)
return 1;
else
return f(n - 1) + f(n - 2);
}
}
IO流
- 与计算机之间数据的传输,可以看做是一种数据的流动
- 以内存为基准,分为 输入input 和 输出 output ,流向内存是输入流,内存流出是的输出流
- 可以理解把程序当中的数据保存到电脑磁盘,为输出流,把电脑磁盘当中的数据加载到程序当中为输入流
IO流的分类
- 根据数据的流向分
- 输入流:把数据从 其他设备 上读取到 内存 中
- 输出流:把数据从 内存 中写出到 其他设备 上
- 根据数据的类型分
- 字节流:以
字节
为单位,读写数据 - 字符流:以
字符
为单位,读写数据
- 字节流:以
顶级父类
- 字节输入流:InputStream
- 字节输出流:OutputStream
- 字符输入流:Reader
- 字符输出流:Writer
字节流
- 一切文件数据(文本、图片、视频等)在存储时,都是以二进制的数字的形式保存的,都一个一个的字节
- 在传输时也是使用字节进行传输,我们称之为
字节流
- 字节流可以传输任意文件数据
- 无论使用什么样的流对象,底层传输的始终为二进制数据
字节输出流
- OutputStream:字节输出流
- java.io.OutputStream 抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地
方法名 | 作用 |
---|---|
public void close() | 关闭此输出流并释放与此流相关联的任何系统资源,close方法,当完成流的操作时,必须调用此方法,释放系统资源 |
public void flush() | 刷新此输出流,并强制任何缓冲的输出字节被写出 |
public void write(byte[] b) | 将 b.length 字节从指定的字节数组写入此输出流 |
public void write(byte[] b, int off, int len) | 从指定的字节数组写入 len 字节,从偏移量 off 开始输出到此输出流 |
public abstract void write(int b) | 将指定的字节输出流 |
-
OutputStream 有很多子类,以上方法子类都可以调用
-
FileOutputStream类
- java.io.FileOutputStream 类是文件输出流,用于将数据写出到文件,继承自OutputStream
构造方法
方法名 | 作用 |
---|---|
public FileOutputStream(File file) | 创建文件输出流写入到指定的 File 对象表示的文件 |
public FileOutputStream(String name) | 创建文件输出流以指定的名称写入文件 |
public class Demo {
public static void main(String[] args) throws FileNotFoundException {
File file = new File("a.txt");
FileOutputStream fos = new FileOutputStream(file);
FileOutputStream fos2 = new FileOutputStream("b.txt");
}
}
🐤注意事项
- 当你创建一个流对象时,必须传入一个文件路径
- 该路径下,如果没有这个文件,会创建该文件。如果有这个文 件,会清空这个文件的数据,写入新的信息
write(int b)
- 写出字节
- 每次只可以写出一个字节数据
public class Demo {
public static void main(String[] args) throws IOException {
File file = new File("a.txt");
FileOutputStream fos = new FileOutputStream(file);
fos.write(97);
fos.write(98);
fos.write(99);
fos.close();
}
}
🐸注意事项
- 虽然参数为 int 类型四个字节,但是只会保留一个字节的信息写出
- 流操作完毕后,必须释放系统资源,调用 close 方法,千万记得
write(byte[] b)
- 写出字节数组
- 可以通过 getBytes 方法把汉字转成字节数组
public class Demo {
public static void main(String[] args) throws IOException {
File file = new File("a.txt");
FileOutputStream fos = new FileOutputStream(file);
byte[] b = "灰灰".getBytes();
fos.write(b);
fos.close();
}
}
write(byte[] b, int off, int len)
- 写出指定长度的字节数组
- 每次写出从 off 索引开始,len个字节
public class Demo {
public static void main(String[] args) throws IOException {
File file = new File("a.txt");
FileOutputStream fos = new FileOutputStream(file);
byte[] b = "abcde".getBytes();
fos.write(b, 2, 2);
fos.close();
}
}
数据追加续写
- 每次程序运行,创建输出流对象,都会清空目标文件中的数据
方法名 | 作用 |
---|---|
public FileOutputStream(File file, boolean append) | 创建文件输出流写入到指定的 File对象表示的文件 |
public FileOutputStream(String name, boolean append) | 创建文件输出流以指定的名称写入文件 |
- 参数介绍
- 参数中都需要传入一个 boolean类型 的值
- true 表示追加数据
- false 表示清空原有数据
public class Demo {
public static void main(String[] args) throws IOException {
File file = new File("a.txt");
FileOutputStream fos = new FileOutputStream(file, true);
byte[] b = "abcde".getBytes();
fos.write(b, 2, 2);
fos.close();
}
}
写出换行
- Windows系统里,换行符号是
\r\n
public class Demo {
public static void main(String[] args) throws IOException {
File file = new File("a.txt");
FileOutputStream fos = new FileOutputStream(file, true);
byte[] b = "abcde".getBytes();
fos.write(b, 2, 2);
fos.write("\r\n".getBytes());
fos.write(b, 2, 2);
fos.close();
}
}
字节输入流
- java.io.InputStream
- java.io.InputStream 抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入 流的基本共性功能方法
基本方法
方法名 | 作用 |
---|---|
public void close() | 关闭此输入流并释放与此流相关联的任何系统资源 |
public abstract int read() | 从输入流读取数据的下一个字节 |
public int read(byte[] b) | 从输入流中读取一些字节数,并将它们存储到字节数组 b 中 |
FileInputStream
- java.io.FileInputStream 类是文件输入流,从文件中读取字节
构造方法
方法名 | 作用 |
---|---|
FileInputStream(File file) | file 是需要读取的文件路径或者是文件对象 |
FileInputStream(String name) | 可以传入一个字符串的路径创建字节输入流 |
public class Demo {
public static void main(String[] args) throws IOException {
File file = new File("a.txt");
FileInputStream fileInputStream = new FileInputStream(file);
FileInputStream fileInputStream1 = new FileInputStream("a.txt");
}
}
🐤注意事项
- 当你创建一个流对象时,必须传入一个文件路径。该路径下,如果没有该文件,会抛出
FileNotFoundException
异常
读取字节数据
- read()方法:每次可以读取一个字节的数据,提升为 int 类型,读取到文件末尾,返回
-1
public class Demo {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("a.txt");
int read = fis.read();
System.out.println((char) read);
int read2 = fis.read();
System.out.println((char) read2);
int read3 = fis.read();
System.out.println((char) read3);
int read4 = fis.read();
System.out.println((char) read4);
int read5 = fis.read();
System.out.println(read5);
}
}
循环的方式优化
public class Demo {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("a.txt");
int b;
while ((b = fis.read()) != -1) {
System.out.println((char) b);
}
}
}
- read(byte[] b)方法:每次读取 b 个长度到字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回
-1
public class Demo {
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("a.txt");
int len;
byte[] b = new byte[2];
while ((len = fis.read(b)) != -1) {
System.out.println(new String(b));
}
fis.close();
}
}
- 复制图片
public class Demo {
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("D:\\logo.jpg");
FileOutputStream fos = new FileOutputStream("copyLogo.jpg");
byte[] b = new byte[1024];
int len;
while ((len = fis.read(b)) != -1) {
fos.write(b, 0, len);
}
fos.close();
fis.close();
}
}
字符流
- 当使用字节流读取文本文件时,可能会有一个小问题
- 就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储
- 所以 Java 提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件
Reader类
- java.io.Reader 抽象类是表示用于读取,字符流的所有类的超类,可以读取字符信息到内存中
- 它定义了字符输入流的基本共性功能方法
基本方法
方法名 | 作用 |
---|---|
public void close() | 关闭此流并释放与此流相关联的任何系统资源 |
public int read() | 从输入流读取一个字符 |
public int read(char[] cbuf) | 从输入流中读取一些字符,并将它们存储到字符数组 cbuf 中 |
FileReader类
- java.io.FileReader 类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区
构造方法
方法名 | 作用 |
---|---|
FileReader(File file) | 传入一个文件对象创建一个字符读取流 |
FileReader(String fileName) | 传入一个字符串路径创建一个字符读取流 |
🐤注意事项
- 当你创建一个流对象时,必须传入一个文件路径。类似于 FileInputStream
读取字符数据
- read方法:每次可以读取一个字符的数据,提升为 int 类型,读取到文件末尾,返回
-1
public class Demo {
public static void main(String[] args) throws Exception {
FileReader fr = new FileReader("a.txt");
int b;
while ((b = fr.read()) != -1) {
System.out.println((char) b);
}
fr.close();
}
}
- read(char[] cbuf):每次读取 b 个长度字符到数组中,返回读取到的有效字符个数, 读取到末尾时,返回
-1
public class Demo {
public static void main(String[] args) throws Exception {
FileReader fr = new FileReader("a.txt");
int len;
char[] chars = new char[2];
while ((len = fr.read(chars)) != -1) {
System.out.println(new String(chars));
}
fr.close();
}
}
- 使用上面这种方法会发现,如果是5个字符的时候会多读取一个,是因为
chars
数组中内容没有被清空 - 指定有效个数
public class Demo {
public static void main(String[] args) throws Exception {
FileReader fr = new FileReader("a.txt");
int len;
char[] chars = new char[2];
while ((len = fr.read(chars)) != -1) {
System.out.println(new String(chars, 0, len));
}
fr.close();
}
}
FileWriter类
- java.io.FileWriter 类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区
构造方法
方法名 | 作用 |
---|---|
FileWriter(File file) | 传入一个文件对象创建一个字符输出流 |
FileWriter(String fileName) | 传入一个字符串路径创建一个字符输出流 |
- 当你创建一个流对象时,必须传入一个文件路径,类似于 FileOutputStream
- write(int b):每次可以写出一个字符数,如果不关闭也就是释放资源,数据只是保存到缓冲区,并未保存到文件
public class Demo {
public static void main(String[] args) throws Exception {
FileWriter fw = new FileWriter("a.txt", true);
fw.write(97);
fw.write('b');
fw.write(30000);
fw.close();
}
}
- 关闭和刷新
- 刷新:因为内置缓冲区的原因,如果不关闭输出流,无法将字符写到文件中。但是关闭了流对象,还想在写入就无法继续写出数据了,如果我们既想写出数据,又想继续使用流,就需要
flush
方法了 - flush:刷新缓冲区,流对象可以继续使用
- close:关闭流,释放系统资源。关闭前会刷新缓冲区
- 刷新:因为内置缓冲区的原因,如果不关闭输出流,无法将字符写到文件中。但是关闭了流对象,还想在写入就无法继续写出数据了,如果我们既想写出数据,又想继续使用流,就需要
public class Demo {
public static void main(String[] args) throws Exception {
FileWriter fw = new FileWriter("a.txt", true);
fw.write(97);
fw.write('b');
fw.write(30000);
fw.flush();
fw.write('d');
fw.close();
}
}
- write(char[] cbuf):每次可以写出字符数组中的数据
public class Demo {
public static void main(String[] args) throws Exception {
FileWriter fw = new FileWriter("a.txt");
String msg = "IT6666灰灰";
char[] chars = msg.toCharArray();
fw.write(chars);
fw.close();
}
}
- write(String str, int off, int len):每次可以写出字符数组中的数据
public class Demo {
public static void main(String[] args) throws Exception {
FileWriter fw = new FileWriter("a.txt");
String msg = "灰灰";
char[] chars = msg.toCharArray();
fw.write(chars, 2, 2);
fw.close();
}
}
异常处理
JDK7之前异常处理中释放资源的是需要自己手动来释放的
public class Demo {
public static void main(String[] args) throws Exception {
FileWriter fw = null;
try {
fw = new FileWriter("a.txt");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
JDK7之后就不用自己来手动释放了,JDK7之后的异常处理会自动帮我们释放只需要把需要释放的资源写在try()的括号中即可
格式
try(创建流对象语句,如果多个使用 ; 隔开){
代码
} catch(IOException e){
e.printStackTrace();
}
- 该语句确保了每个资源在语句结束时自动关闭释放资源
public class Demo {
public static void main(String[] args) throws Exception {
try (FileWriter fw = new FileWriter("a.txt"); FileReader fr = new FileReader("a.txt")) {
fw.write("it6666.top");
int read = fr.read();
} catch (IOException e) {
e.printStackTrace();
}
}
}
缓冲流
- 缓冲流,也叫高效流,是对4个基本的 File*** 流的增强
- 所以也是4个流,按照数据类型分类
- 字节缓冲流: BufferedInputStream , BufferedOutputStream
- 字符缓冲流: BufferedReader,BufferedWriter
基本原理
- 缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组
- 通过缓冲区读写,减少系统 IO 次数,从而提高读写的效率
字节缓冲流
构造方法
方法名 | 作用 |
---|---|
public BufferedInputStream(InputStream in) | 创建一个 新的缓冲输入流 |
public BufferedOutputStream(OutputStream out) | 创建一个新的缓冲输出流 |
public class Demo {
public static void main(String[] args) throws Exception {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("a.txt"));
}
}
效率测试
直接使用 FileInputStream 与 FileOutStream 复制文件
public class Demo {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("D:\\view.mp4");
FileOutputStream fos = new FileOutputStream("newView.mp4");
int len;
byte[] b = new byte[1024];
while ((len = fis.read(b)) != -1) {
fos.write(b);
}
fis.close();
fos.close();
long end = System.currentTimeMillis();
System.out.println("时间:" + (end - start));
}
}
使用缓冲流复制文件
public class Demo {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\view.mp4"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("newView.mp4"));
int len;
byte[] b = new byte[1024];
while ((len = bis.read(b)) != -1) {
bos.write(b);
}
bis.close();
bos.close();
long end = System.currentTimeMillis();
System.out.println("时间:" + (end - start));
}
}
字符缓冲流
构造方法
方法名 | 作用 |
---|---|
public BufferedReader(Reader in) | 创建一个 新的缓冲字符输入流 |
public BufferedWriter(Writer out) | 创建一个新的缓冲字符输出流 |
public class Demo {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
}
}
特有方法
方法名 | 作用 |
---|---|
public String readLine() | 读一行文字 |
public void newLine() | 写一行分隔符,由系统属性定义符号 |
public class Demo {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
}
}
public class Demo {
public static void main(String[] args) throws Exception {
BufferedWriter br = new BufferedWriter(new FileWriter("a.txt"));
br.write("灰灰");
br.newLine();
br.write("IT6666.top");
br.newLine();
br.close();
}
}
转换流
字符编码
- 计算机中储存的信息都是用
二进制
数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制 数转换之后的结果 - 按照某种规则,将字符存储到计算机中,称为编码
- 反之,将存储在计算机中的二进制数按照以某种规则解析显示出来,称为解码
- 按照A规则存储,同样按照A规则解析,那么就能显示正确的文本符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象
字符集
- 字符集 Charset:也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等
- 计算机要准确的存储和识别各种字符集符号,需要进行字符编码,一套字符集必然至少有一套字符编码
- 常见字符集有ASCII字符集、GBK字符集、Unicode字符集等
🐤常见字符集
- ASCII字符集:ASCII编码
- GBK字符集:GBK编码
- Unicode字符集:UTF8编码、UTF16编码、UTF32编码
- 当指定了编码,它所对应的字符集自然就指定了,所以编码才是我们最终要关心的
🐸字符集介绍
ASCII字符集
- ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)
- 是基于拉丁字母的一套电脑编码系统,用于显示现代英语
- 主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)
- 基本的ASCII字符集,使用7位(bits)表示一个字符,共128字符
- ASCII的扩展字符集使用8位(bits) 表示一个字符,共256字符,方便支持欧洲常用字符
ISO-8859-1字符集
- 拉丁码表,别名Latin-1,用于显示欧洲使用的语言,包括荷兰、丹麦、德语、意大利语、西班牙语等
- ISO-5559-1使用单字节编码,兼容ASCII编码
GBxxx字符集
- GB就是国标的意思,是为了显示中文而设计的一套字符集
- GB2312
- 简体中文码表。一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字
- 这样大约可以组合了包含7000多个简体汉字
- 此外数学符号、罗马希腊的字母、日文的假名们都编进去了
- 在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码
- 这就是常说的
全角
字符,而原来在127号以下的那些就叫半角
字符了
- GBK
- 最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案
- 共收录了 21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等
- GB18030
- 新的中文码表。收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成
- 支持中国国内少数民族的文字,同时支持繁体汉字以及日韩汉字等
Unicode字符集
- Unicode编码系统为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码
- 它最多使用4个字节的数字来表达每个字母、符号,或者文字。有三种编码方案
- UTF-8、UTF-16和UTF32,最为常用的UTF-8编码
- UTF-8编码,可以用来表示Unicode标准中任何字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码
UTF8编码规则
- 128个US-ASCII字符,只需一个字节编码
- 拉丁文等字符,需要二个字节编码
- 大部分常用字(含中文),使用三个字节编码
- 其他极少使用的Unicode辅助字符,使用四字节编码
编码引出的问题
- 在IDEA中,使用 FileReader 读取项目中的文本文件。由于IDEA的设置,都是默认的 UTF-8 编码,所以没有任何问题
- 但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码
public class Demo {
public static void main(String[] args) throws Exception {
FileReader fileReader = new FileReader("d:/demo.txt");
int read;
while ((read = fileReader.read()) != -1) {
System.out.println((char) read);
}
fileReader.close();
}
}
🐤解决乱码
InputStreamReader
- 转换流 java.io.InputStreamReader,是Reader的子类,是从字节流到字符流的桥梁
- 它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集
构造方法
方法名 | 作用 |
---|---|
InputStreamReader(InputStream in) | 创建一个使用默认字符集的字符流 |
InputStreamReader(InputStream in, String charsetName) | 创建一个指定字符集的字符流 |
public class Demo {
public static void main(String[] args) throws Exception {
InputStreamReader isr = new InputStreamReader(new FileInputStream("d://demo.txt"), "gbk");
int read;
while ((read = isr.read()) != -1) {
System.out.println((char) read);
}
isr.close();
}
}
OutputStreamWriter
- 转换流 java.io.OutputStreamWriter,是Writer的子类,是从字符流到字节流的桥梁
- 使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集
构造方法
方法名 | 作用 |
---|---|
OutputStreamWriter(OutputStream in) | 创建一个使用默认字符集的字符流 |
OutputStreamWriter(OutputStream in, String charsetName) | 创建一个指定字符集的字符流 |
public class Demo {
public static void main(String[] args) throws Exception {
String fileName1 = "d://demo.txt";
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(fileName1));
osw.write("灰灰");
osw.close();
String fileName2 = "d://demoTwo.txt";
OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(fileName2), "gbk");
osw2.write("灰灰");
osw2.close();
}
}
序列化
- 用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象中存储的属性等信息
- 字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息
- 字节序列还可以从文件中读取回来,重构对象,对它进行反序列化
序列化必须满足两个条件
- 该类必须实现 java.io.Serializable 接口
- Serializable 是一个标记接口,不实现此接口的类将不会被序列化或反序列化,会抛出 NotSerializableException
- 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用 transient 关键字修饰
ObjectOutputStream类
- 将Java对象的原始数据类型写出到文件,实现对象的持久存储
构造方法
方法名 | 作用 |
---|---|
public ObjectOutputStream(OutputStream out) | 创建一个指定 OutputStream 的 ObjectOutputStream |
写出对象方法
- public final void writeObject (Object obj)
- 创建Person类
public class Person implements java.io.Serializable {
public String name;
public String age;
public transient String address;
public void show() {
System.out.println("myName is " + name);
}
}
- 写到文件当中
public class Demo {
public static void main(String[] args) throws Exception {
Person person = new Person();
person.name = "IT6666";
person.age = "23";
person.address = "上海";
FileOutputStream fos = new FileOutputStream("person.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(person);
oos.close();
fos.close();
}
}
ObjectInputStream类
- ObjectInputStream 反序列化流,将之前使用 ObjectOutputStream 序列化的原始数据恢复为对象
构造方法
方法名 | 作用 |
---|---|
public ObjectInputStream(InputStream in) | 创建一个指定 InputStream 的 ObjectInputStream |
读取对象方法
- readObject()
public class Demo {
public static void main(String[] args) throws Exception {
FileInputStream fileIn = new FileInputStream("person.txt");
ObjectInputStream in = new ObjectInputStream(fileIn);
Person p = (Person) in.readObject();
System.out.println(p.name);
System.out.println(p.age);
System.out.println(p.address);
p.show();
fileIn.close();
in.close();
}
}
注意事项
- 对于 JVM 可以反序列化对象,它必须是能够找到 class 文件的类
- 如果找不到该类的 class 文件,则抛出一个 ClassNotFoundException 异常
打印流
- 我们在控制台打印输出,是调用 print 方法和 println 方法完成的
- 这两个方法都来自于 java.io.PrintStream 类
- 该类能够方便地打印各种数据类型的值,是一种便捷的输出方式
使用指定的文件名创建一个新的打印流
- public PrintStream(String fileName)
- System.out 就是 PrintStream 类型的,只不过它的流向是系统规定的,打印在控制台上
public class Demo {
public static void main(String[] args) throws Exception {
System.out.println("it6666.top");
PrintStream os = new PrintStream("demo.txt");
System.setOut(os);
System.out.println("it6666.top");
}
}