一、转换流
转换流的学习,先要了解字符编码
1. 字符编码与解码
-
编码:把字符(字母、英文、标点符号、中文)等字符按照某种规则转换为二进制数据(字节数据)存储在计算机中
-
解码:将存储在计算机中的二进制数据按照某种规则解码显示出来
-
乱码原因:用规则
A
编码,也一定要用规则A
解码,如果用规则B
解码则会出现乱码 -
解码:
String(byte[] bytes, String charsetName):通过指定的字符集解码字节数组
-
编码:
byte[] getBytes(String charsetName):使用指定的字符集合把字符串编码为字节数组
使用示例
public class Charset_Demo01 {
public static void main(String[] args) throws UnsupportedEncodingException {
//0. 编码
String s = "字符编码";
byte[] bytes = s.getBytes("gbk");
//1. 解码
String s1 = new String(bytes,"gbk");
System.out.println(s1);
}
}
- 输出
2. 字符集
- 字符编码
Character Encoding
就是一套字符与二进制数之间的对应规则 - 字符集
Charset
:也叫编码表,是一个系统支持所有字符的集合 - 一套字符集下面至少存在一种编码方式,常见的字符集如下:
- 可见字符编码和字符集是一一对应的,指定了编码,则对应的字符集也就随之确定了
下面简单的介绍一下常见的字符集
-
ASCII字符集
- ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)。
- 基本的ASCII字符集,使用7位(bits)表示一个字符,共128字符。ASCII的扩展字符集使用8位(bits)表示一个字符,共256字符,方便支持欧洲常用字符。
-
ISO-8859-1字符集
- 拉丁码表,别名Latin-1,用于显示欧洲使用的语言,包括荷兰、丹麦、德语、意大利语、西班牙语等。
- ISO-8859-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和UTF-32。最为常用的UTF-8编码。
- UTF-8编码,可以用来表示Unicode标准中任何字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。所以,我们开发Web应用,也要使用UTF-8编码。它使用一至四个字节为每个字符编码,编码规则:
- 8个US-ASCII字符,只需一个字节编码。
- 拉丁文等字符,需要二个字节编码。
- 大部分常用字(含中文),使用三个字节编码。
- 其他极少使用的Unicode辅助字符,使用四字节编码。
3. 编码问题导致的乱码
- 在Java开发工具
IDEA
中,使用FileReader
读取项目中的文本文件,由于IDEA
默认设置UTF-8
便阿门,所有没有问题。但是读取Windows创建的文本文件的时候,Windows默认的是GBK
编码,就会出现乱码
下面将演示这个问题
-
在windows下新建一个文本文件
-
使用
FileReader
读取
public class Charset_Demo02 {
public static void main(String[] args) throws IOException {
//0. 新建FileReader对象
FileReader fr = new FileReader("D:\\IO流学习\\gbk.txt");
int len;
while ((len = fr.read()) != -1){
System.out.print((char)len);
}
}
}
- 输出
- 那么如何解决这个问题呢?也就是如何读取
GBK
编码方式的文件呢! - 这个时候就需要转换流了
4. InputStreamReader类–(字节流到字符流的桥梁)
java.io.InputStreamReader
,是Reader
的子类- 字面意思就能看出从字节输入流最后到了字符输入流
- 它本质上是读取字节,然后使用指定的字符集将字节解码为字符
- 字符集可以自己指定
- 也可以使用默认的字符集
4.1 构造方法
public InputStreamReader(InputStream in)
:创建一个使用默认字符集的字符流,注意参数是一个InpunStream
的对象public InputStreamReader(InputStream in, String charsetName)
:创建一个使用指定字符集的字符流
具体使用
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\IO流学习\\gbk.txt"));
InputStreamReader isr1 = new InputStreamReader(new FileInputStream("D:\\IO流学习\\gbk.txt"),"GBK");
4.2 解决编码问题
以上面在Windows
下创建的GBK
编码的文件的读取为例子
public class Charset_Demo02 {
public static void main(String[] args) throws IOException {
//0. 使用默认的utf-9
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\IO流学习\\gbk.txt"));
//1. 使用指定的gbk编码
InputStreamReader isr1 = new InputStreamReader(new FileInputStream("D:\\IO流学习\\gbk.txt"),"GBK");
System.out.println("使用默认utf-8的读取效果");
int len;
while ((len = isr.read()) != -1){
System.out.print((char)len);
}
System.out.println();
System.out.println("使用指定的gbk的读取效果");
while ((len = isr1.read()) != -1){
System.out.print((char)len);
}
}
}
- 输出
5. OutputStreamWriter–字符流到字节流的桥梁
起始这个也很好理解,首先这显然是一个输出流,既然是输出流,那么就一定是把内存中的数据写入到磁盘上,然后以字节(二进制)的形式存储。这个过程显然就是程序中的字符到磁盘上的字节的转换过程。
5.1 构造方法
OutputStreamWriter(OutputStream os)
:使用默认字符集的字符流OutputStreamWriter(OutputStream os, String charsetName)
:创建一个指定字符集的字符流
5.2 指定编码输出数据
public class Charset_Demo03 {
public static void main(String[] args) throws IOException {
//0. 创建默认字符集编码的 字符输出流
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\IO流学习\\utf.txt"));
//1. 创建指定字符集编码的 字符输出流
OutputStreamWriter osw1 = new OutputStreamWriter(new FileOutputStream("D:\\IO流学习\\gbk.txt"),"gbk");
//2. 分别写入数据s
osw.write("按默认编码输出的数据");
osw1.write("按指定gbk编码输出的数据");
//3. 关闭流
osw.close();
osw1.close();
}
}
- 输出
6. 小结
目前学过的流的一个小节
二、序列化流
序列化相关问题请参考文章https://blog.csdn.net/fat_cai_niao/article/details/105051846
知道相关的序列化类及其构造函数:
ObjectOutputStream
public ObjectOutputStream(OutputStream out)
public final void writeObject(Object obj)
ObjectInputStream
public ObjectInputStream(InputStream in)
public final Object readObject()
三、打印流
1. 什么是打印流?
- 在控制台打印信息的时候调用
print()
和println()
方法完成的 - 这个两个方法本质上都来自
java.io.PrintStream
类 - 该类可以方便的打印各种类型的值,是一种便捷的输出设备
1.1 打印流分类
- 字节打印流:
PrintStream
- 字符打印流:
PrintWriter
1.2 打印流特点
- 只操作目的地,不操作数据源
- 可以操作任意类型的数据
- 如果启用了自动刷新,调用
println()
方法时,能够换行并刷新 - 可以直接操作文件
那些流可以直接操作文件呢?
- 该流的构造方法能够同时接收
File
和String
类型参数的时候,一般都是可以直接操作文件的
2. 字节输出打印流PrintStream复制文本文件
public class Print_Demo01 {
public static void main(String[] args) throws IOException {
//0. 新建 缓冲字符输入流
BufferedReader br = new BufferedReader(new FileReader("D:\\IO流学习\\a.txt"));
//1. 新建 打印输出流
PrintStream ps = new PrintStream("D:\\IO流学习\\a_printCopy.txt");
//2. 按行复制文件
String line;
while ((line = br.readLine()) != null){
ps.println(line);
}
br.close();
ps.close();
}
}
- 输出
3. 字符打印输出流PrintWriter复制文本文件
public class Print_Demo03 {
public static void main(String[] args) throws IOException {
//0. 新建 缓冲字符输入流
BufferedReader br = new BufferedReader(new FileReader("D:\\IO流学习\\a.txt"));
//1. 新建 打印输出流
PrintWriter pw = new PrintWriter("D:\\IO流学习\\a_printCopy_01.txt");
//2. 按行复制文件
String line;
while ((line = br.readLine()) != null){
pw.println(line);
}
br.close();
pw.close();
}
}
- 输出
四、Properties属性类
1. 概述
-
是一个集合类
-
java.util.Properties
继承于Hashtable
class Properties extends Hashtable<Object,Object>
-
表示一个持久的属性集,使用键值结构存储数据,每个键值都是一个字符串
-
该类被多种
Java
类使用,比如获取系统属性System.getProperties()
返回的就是一个Properties
对象
1.1 特有功能
Object setProperty(String key, String value)
public String getProperty(String key)
public Set<String> stringPropertyNames()
1.2 与流结合的功能
输出:把内存中的集合类存储到文本文件中
public void store(Writer writer, String comments)
public void store(OutputStream out, String comments)
输入:把键值对形式的文本文件内容加载到内存中的集合
void load(InputStream inStream)
void load(Reader reader)
2. 构造方法
public Properties() {
this(null);
}
3. 基本存储方法
Object setProperty(String key, String value)
:保存一对键值对public String getProperty(String key)
:根据键,获取值public Set<String> stringPropertyNames()
:获取所有的键
使用
public class Properties_Demo01 {
public static void main(String[] args) {
//0. 创建属性对象
Properties properties = new Properties();
//1. 添加键值对
properties.setProperty("fileName", "pro.txt");
properties.setProperty("length", "20985038");
properties.setProperty("location", "D:\\IO流学习\\pro.txt");
//2. 打印属性集对象
System.out.println(properties);
//3. 通过键获取值
System.out.println(properties.getProperty("fileName"));
System.out.println(properties.getProperty("length"));
System.out.println(properties.getProperty("location"));
//4. 获取所有的键名 并遍历
Set<String> names = properties.stringPropertyNames();
for (String name : names) {
System.out.println(name + "---->" + properties.getProperty(name));
}
}
}
- 输出
4. 与流相关
void load(InputStream inStream)
:从字节输入流中获取键值对
因为参数中使用了字节输入流,可以关联到某文件,这样就可以加载文本中的数据了。就是可以把文件中的键值对加载到内存中,常用于配置文件。
public class Properties_Demo02 {
public static void main(String[] args) throws IOException {
//0. 创建属性对象
Properties properties = new Properties();
//1. 加载文本信息到属性集
properties.load(new FileInputStream("D:\\IO流学习\\pro.txt"));
//2. 遍历并打印
Set<String> set = properties.stringPropertyNames();
for (String key : set) {
System.out.println(key + "--->" + properties.getProperty(key));
}
}
}
- 输出