1、常见字符编码
1.1、ACSII码
美国信息交换标准代码,是一种基于拉丁字母的字符编码标准。用一个字节来表示一个字符,共8位,首位是数字0,后7位二进制数表示(即128)个字符。其中,(十进制)数字0对应48,大写字母A对应65,小写字母a对应97。
1.2、GBK
是一种汉字编码标准,由中国国家标准总局发布。用两个字节来表示一个字符,共16位,首位是1,后15位二进制数表示个字符。它兼容GB 2312编码,共收录了21886个汉字和符号,覆盖了绝大部分常用的汉字。
1.3、UTF-8
是当下使用最广泛的一种字符编码,是一种针对 Unicode 的可变长度字符编码,使用 1 到 4 个字节来表示每个字符,与 ASCII 兼容。
- 1 字节:0xxxxxxx(ASCII 字符)
- 2 字节:110xxxxx 10xxxxxx
- 3 字节:1110xxxx 10xxxxxx 10xxxxxx(常用汉字字符)
- 4 字节:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
注意:编码与解码时使用的字符集如果不相同,一般会出现乱码问题(数字,字母一般不会乱码)
2、字节流
2.1、字节输入流InputStream的实现类文件字节输入流FileInputStream
FileInputStream:从文件中按字节读取
常用构造器:
// 通过指定文件路径创建 FileInputStream
FileInputStream(String name) throws FileNotFoundException
// 通过 File 对象创建 FileInputStream
FileInputStream(File file) throws FileNotFoundException
常用方法:
// 从输入流中读取一个字节的数据,返回字节的整数值,如果到达文件末尾则返回 -1
int read() throws IOException
// 从输入流中读取多个字节数据并存储在字节数组 b 中,返回实际读取的字节数,如果到达文件末尾则返回 -1
int read(byte[] b) throws IOException
// 从输入流中读取最多 len 个字节的数据并存储在字节数组 b 中,从 off 位置开始存储,返回实际读取的字节数,如果到达文件末尾则返回 -1
int read(byte[] b, int off, int len) throws IOException
// 跳过并丢弃输入流中的 n 个字节数据,返回实际跳过的字节数
long skip(long n) throws IOException
// 关闭输入流并释放与之相关的系统资源
void close() throws IOException
测试用例:
当使用 FileInputStream
读取包含中文的文本文件
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class ReadFile {
public static void main(String[] args) {
try (InputStream is = new FileInputStream("a.txt")) {
int content;
while ((content = is.read()) != -1) {
System.out.print((char) content);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
is.close();
}
}
}
乱码问题:
上述代码可能会出现乱码问题。这是因为 FileInputStream
是按字节读取文件的,读取包含中文的文本文件时,中文字符通常占用多个字节(如 UTF-8 编码下,一个中文字符通常占用 3 个字节)。如果直接将这些字节转换为字符,可能会导致字符编码不匹配,从而出现乱码。
解决:
1、一次性读完文件所有字节。
2、使用高级流读取(以后再讲)。
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class ReadFile {
public static void main(String[] args) throws Exception { // 不推荐直接抛异常
File file = new File("a.txt");
InputStream inputStream = new FileInputStream(file);
// 方式1
long size = file.length();
byte[] b1 = new byte[(int)size]; // 仅适用文件不会超过int的最大值的情况
int len;
while((len =i nputStream.read(b1)) != -1){
System.out.println(new String(b1,0,len));
}
// 方式2
byte[] b2 = inputStream.readAllBytes();
System.out.println(new String(b2));
inputStream.close();
}
}
2.2、字节输出流OutputStream的实现类文件字节输入流FileOutputStream
FileOutputStream
:通常用于写入字节数据到文件中。
常用构造器:
// 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
public FileOutputStream(File file);
// 创建一个向指定 File 对象表示的文件中写入数据的文件输出流,如果第二个参数为 true,则将字节写入文件末尾而不是文件开头(追加)。
public FileOutputStream(File file, boolean append);
// 创建一个向具有指定名称的文件中写入数据的文件输出流。
public FileOutputStream(String name);
// 创建一个向具有指定名称的文件中写入数据的文件输出流,如果第二个参数为 true,则将字节写入文件末尾而不是文件开头(追加)。
public FileOutputStream(String name, boolean append);
常用方法:
// 将指定字节写入此文件输出流。
public void write(int b);
// 将指定字节数组中的字节写入此文件输出流。
public void write(byte[] b);
// 将指定字节数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
public void write(byte[] b, int off, int len);
// 关闭此文件输出流并释放与此流关联的所有系统资源。
public void close();
// 刷新此输出流并强制写出所有缓冲的输出字节。
public void flush();
测试用例:
使用 FileOutputStream
将字符串写入文件
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamExample {
public static void main(String[] args) {
String s= "Hello, World!";
try (OutputStream os = new FileOutputStream("b.txt")) {
byte[] byteArray = s.getBytes();
os.write(byteArray);
} catch (IOException e) {
e.printStackTrace();
} finally {
os.close();
}
}
}
3、释放资源方式
3.1、try-catch-finally
try {
//定义资源
// 可能出现异常的代码块
} catch(Exception e) {
// 异常处理
} finally {
// 无论try中代码块是否正常执行还是出现异常,此处的代码都会执行,即使有return;也仍然会执行,除非直接终止JVM
// 将流的关闭放在此处可保证流可以正常关闭释放资源
}
3.2、try-with-resource
try(定义资源1; 定义资源2;) { // 将定义对象放在此处,当使用完后,系统会自动帮我们管理资源,不需要我们手动释放
//可能异常代码块
} catch(Exception e) {
//异常处理
}