字符集
美国人发明计算机
要将他们的字符存入计算机(英文字母、数字、标点、特殊字符)
给字符进行编号,组成了一张ASCII码表(美国信息交换标准代码),一共包含128个字符
该码表以1个字节存储1个字符,首位都是0
中文的字符存不下
所以我们推出了GBK(汉字内码扩展规范,国标)
该码表以2个字节存储1个字符,包含了2万多个汉字字符
GBK兼容了ASCII,但是规定汉字的首位是1
各个国家都推出自己的字符集
国际组织制定了Unicode万国码,它可以容纳世界上所有的文字、符号
Unicode最初的编码方式为UTF-32,统一以4个字节存储1个字符,这样存储的弊端是占用存储空间且通信效率低
所以后来流行了UTF-8编码方式,它采取可变长编码方案
英文字符、数字等只占1个字节,且兼容标准ASCII编码,汉字字符占用3个字节
注意
Windows里的ANSI其实是Windows code pages,这个模式根据当前locale选定具体的编码
比如简体中文locale下是GBK,在ASCII范围内是和ASCII一致的
编码
UTF-8
是Unicode字符集的一种编码方案,采取可变长编码方案,总共分为四个长度区(1到4个字节)
由于兼容ASCII码表,所以英文、数字只占1个字节,汉字占3个字节
UTF-8是我们实际开发最常见的码表
UTF-8编码方案(二进制)
0xxxxxxx(ASCII码)
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
重点记忆
ASCII字符集: 只有英文、数字、符号等,占1个字节
GBK字符集:汉字占2个字节,英文、数字、符号等占1个字节
UTF-8编码方案:汉字占3个字节,英文、数字、符号等占1个字节
注意事项
编码时使用的字符集,和解码时使用的字符集必须一致,否则可能出现乱码
英文、数字一般不会乱码,因为很多字符集都兼容了ASCII编码
String提供了如下方法 | 说明 |
byte[] getBytes() | 使用平台默认的字符集将该String编码为一系列字节,将结果存储到新的字节数组中 |
byte[] getBytes(String charsetName) | 使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中 |
解码
String提供了如下方法 | 说明 |
String(byte[] bytes) | 通过平台默认的字符集,解码指定的字节数组来构造新的String |
String(byte[] bytes, String charsetName) | 通过指定的字符集,解码指定的字节数组来构造新的String |
如何使用Java程序对字符进行编码?
String类的方法 byte[] getBytes():默认字符集编码
byte[] getBytes(String charsetName):指定字符集编码
如何使用Java程序对字节进行解码?
String类的构造器 String(byte[] bytes):使用默认字符集解码
String(byte[] bytes, String charsetName):指定字符集解码
IO流
- 字节输入流:以内存为基准,将来自磁盘文件、网络中的数据以字节的形式读入到内存中去的流
- 字节输出流:以内存为基准,将内存中的数据以字节写出到磁盘文件或者网络中去的流
- 字符输入流:以内存为基准,来自磁盘文件、网络中的数据以字符的形式读入到内存中去的流
- 字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络中去的流
IO流的作用?
读、写文件数据的
IO流是怎么划分的,大体分为几类,各自的作用?
字节输入流 InputStream(读字节数据的) 字节输出流 OutoutStream(写字节数据出去的) 字符输入流 Reader(读字符数据的) 字符输出流 Writer(写字符数据出去的)
FileInputStream(字节输入流)
构造器 | 说明 |
public FileInputStream(File file) | 创建字节输入流管道与源文件接通 |
public FileInputStream(String pathname)(常用底层封装了new File) | 创建字节输入流管道与源文件接通 |
方法名称 | 说明 |
public int read() | 每次读取一个字节返回,如果发现没有数据可读会返回-1. |
public int read(byte[] buffer) | 每次用一个字节数组去读取数据,返回字节数组读取了多少个字节,如果发现没有数据可读会返回-1 |
public class Demo {
public static void main(String[] args) throws Exception {
//1、创建字节输入流,关联文件
FileInputStream fis = new FileInputStream("day09\\Demo06.txt");
//2、循环读,读到文件末尾(-1)停止
int b;
while ((b = fis.read()) != -1) {
System.out.print((char) b); //abcdecfé»é©¬ 中文现乱码
}
//3、释放资源
fis.close();
}
}
使用FileInputStream每次读取一个字节,读取性能较差,并且读取汉字输出会乱码
文件字节输入流的作用是什么?
将数据以字节的形式读取到内存
每次读取一个字节的方法是哪个?
public int read();
每次读取一个字节存在什么问题?
读取性能较差,每次读取一个字节都需要和硬盘交互 将中文拆分读取,必定乱码 流使用完需要关闭(释放资源),否则占用资源别人就不能用了
public class Demo {
public static void main(String[] args) throws Exception {
//创建字节输入流对象,关联文件
FileInputStream fis = new FileInputStream("day09\\Demo07.txt");
//一次读多个字节(使用数组一次读多个)
byte[] bytes = new byte[3];
//public int read(byte[] buffer); 用字节数组读数据,返回读取到的有效字节个数,读到文件末尾(没读到有效内容)会返回-1
int len = fis.read(bytes);
System.out.println("本次读取到的有效字节个数:" + len);
System.out.println(new String(bytes, 0, len));
int len2 = fis.read(bytes);
System.out.println("本次读取到的有效字节个数:" + len2);
System.out.println(new String(bytes, 0, len2));
//释放资源
fis.close();
}
}
使用FileInputStream每次读取多个字节,读取性能得到了提升,但读取汉字输出还是会乱码
文件字节输入流:一次读取完全部字节
方法名称 | 说明 |
public byte[] readAllBytes() throws IOException | 直接将当前字节输入流对应的文件对象的字节数据装到一个字节数组返回 |
*/
//创建流对象,关联文件
FileInputStream fis = new FileInputStream("day09\\Demo09.txt");
//一次性读完所有字节
byte[] bytes = fis.readAllBytes(); //注意:如果文件过大(数组长度 > Integer.MAX_VALUE),底层或抛异常
//展示数据
System.out.println(new String(bytes));
如何使用字节输入流读取中文内容输出时不乱码呢?
一次性读取完全部字节 可以定义与文件一样大的字节数组读取,也可以使用官方API 直接把文件数据全部读取到一个字节数组可以避免乱码,
是否存在问题?
如果文件过大,定义的字节数组可能引起内存溢出
FileOutputStream(文件字节输出流)
作用:以内存为基准,把内存中的数据以字节的形式写出到文件中去
构造器 | 说明 |
public FileOutputStream(File file) | 创建字节输出流管道与源文件对象接通 |
public FileOutputStream(String filepath) | 创建字节输出流管道与源文件路径接通 |
public FileOutputStream(File file,boolean append) | 创建字节输出流管道与源文件对象接通,可追加数据 |
public FileOutputStream(String filepath,boolean append) | 创建字节输出流管道与源文件路径接通,可追加数据 |
方法名称 | 说明 |
public void write(int a) | 写一个字节出去 |
public void write(byte[] buffer) | 写一个字节数组出去 |
public void write(byte[] buffer , int pos , int len) | 写一个字节数组的一部分出去 |
public void close() throws IOException | 关闭流 |
如何创建字节输出流管道,如何实现写数据的追加操作?
public FileOutputStream(String pathname); 在构造第二个参数传递true,默认为false表示不追加
字节输出流写数据的方法有哪些?
public void write(int a); 写一个字节
public void write(byte[] bytes); 写一个字节数组
public void write(byte[] bytes, int pos, int len);
写一个字节数组的一部分 字节输出流如何实现写出去的数据可以换行?
如果要写换行,需要写“\r\n”的字节数组表示形式
public class Demo {
public static void main(String[] args) throws Exception {
//public FileOutputStream(String pathname); 创建字节输出流关联文件,文件不存在则创建,存在则清空内容
OutputStream os = new FileOutputStream("day09\\Demo10.txt", true);
//public void write(int a); 写一个字节
os.write(65);
os.write(66);
os.write(67);
//注意1、如果要写换行,需要写"\r\n"的字节数组表示形式
os.write("\r\n".getBytes());
//public void write(byte[] bytes); 写一个字节数组
byte[] bytes = {48, 49, 50, 51, 52};
os.write(bytes);
os.write("\r\n".getBytes());
//public void write(byte[] bytes, int pos, int len); 写一个字节数组的一部分
//需求:写出字节数组最后三个字节
os.write(bytes, 2, 3);
os.write("\r\n".getBytes());
//释放资源
os.close();
}
}
文件的复制
任何文件的底层都是字节,字节流做复制,是一字不漏的转移完全部字节,只要复制后的文件格式一致就没问题!
public class Demo02 {
public static void main(String[] args)throws Exception {
FileInputStream fis = new FileInputStream("E:\\Demo09.txt");
FileOutputStream os = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\copy.txt");
//边读边写:一次读写一个字节
/* int b;
while ((b=fis.read())!=-1){
os.write(b);
}*/
//边读编写,一次读取多个;
int len;
byte[] bytes = new byte[1024 * 3];
while ((len = fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
}
}
try-catch-finally
finally特点:无论try中的程序是正常执行了,还是出现了异常,最后都一定会执行finally区,除非JVM终止
作用:用于在程序执行完成后进行资源的释放操作(专业级做法)
package com.demo12_IO流_释放资源1;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/*
try-catch-finally
finally代码块写在try-catch的最后面
无论try中程序是否正常正式,最后一定会执行finally中的代码,除非JVM终止
注意不要在finally代码块中返回结果,会扰乱运行结果
finally代码块作用
目前多用于释放资源
*/
// TODO: 能够说出 IO流资源释放的方式有哪些
public class Demo {
public static void main(String[] args) {
//method();
//System.out.println(getSum(10, 20)); //错误结果100
/*
需求:捕获下面代码中的异常,并正确的释放资源
*/
//提升作用域
InputStream is = null;
try {
//在这里出现了异常,直接进入catch环节,后面的代码就不会执行了
System.out.println(10 / 0);
is = new FileInputStream("day09\\Demo05.txt");
System.out.println(is.read());
} catch (IOException e) {
e.printStackTrace();
} finally {
//释放资源
try {
if (is != null) {
//is有可能是null,所以加上非空判断(如果is是null,没有必要做释放资源)
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static int getSum(int a, int b) {
try {
return a + b;
} catch (Exception e) {
e.printStackTrace();
} finally {
//注意不要在finally代码块中返回结果,会扰乱运行结果
return 100;
}
}
public static void method() {
try {
//无论try中程序是否正常正式,最后一定会执行finally中的代码,除非JVM终止
System.out.println(10 / 0); //数学运算异常
} catch (Exception e) {
e.printStackTrace();
} finally { //finally代码块写在try-catch的最后面
System.out.println("finally..");
}
}
}
try-with-resource
该资源使用完毕后,会自动调用其close()方法,完成对资源的释放
- 小括号()中只能放置资源,否则报错;
- 资源指的是最终实现了AutoCloseable接口.
package com.demo13_IO流_释放资源2;
/*
try-with-resource
JDK7开始提供的释放资源方式,编码更简洁
try后面小括号中只能定义资源对象,最终底层会帮我们释放这些对象
资源指实现了AutoCloseable接口的对象
Closeable是AutoCloseable的子接口
public interface Closeable extends AutoCloseable {
public void close() throws IOException;
..
}
书写格式
try(要释放的资源对象1, 资源对象2..){
}catch(Exception e){
处理异常的代码
}
*/
// TODO: 能够说出 IO流资源释放的方式有哪些
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Random;
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
/*
需求:捕获下面代码中的异常,并正确的释放资源
*/
try (
//定义资源(字节输入流)
InputStream is = new FileInputStream("day09\\Demo05.txt");
) {
//业务逻辑
System.out.println(is.read());
} catch (Exception e) {
e.printStackTrace();
}
}
}