1、字符编码(Character encoding)和编码集(Character set)

字符编码(Character encoding)是将字符转为字节或字节数组的过程。

字符集(Character set)是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集有:ASCII字符集GB2312字符集GB18030字符集Unicode字符集 等。

计算机要准确的识别和存储各种文字,就需要进行字符编码。中文文字数目大,而且还分为简体中文和繁体中文,而计算机最初是按英语单字节字符设计的,因此,对中文字符进行编码,是中文信息交流的技术基础。

常见字符集:

ASCII(American Standard Code for Information Interchange,美国信息互换标准编码)是基于罗马字母表的一套电脑编码系统,主要用于显示现代英语和其他西欧语言,是现今最通用的单字节编码系统,并等同于国际标准 ISO 646

GB2312 又称为 GB2312-80 字符集,全称为《信息交换用汉字编码字符集•基本集》,1981年5月1日实施。收录的汉字已经覆盖99.75%的使用频率,基本满足了汉字的计算机处理需要。

GB 18030 的全称是 GB18030-2000《信息交换用汉字编码字符集基本集的扩充》,是2000年3月17日发布的新的汉字编码标准,2001年8月31日后在中国市场上发布的软件必须符合本标准。

Unicode 字符集编码全称是 Universal Multiple-Octet Coded Character Set,是由 Unicode 学术学会(Unicode Consortium)制订的字符编码系统,支持现今世界各种不同语言书面文本的交换、处理及显示。

UTF-8(8-bit Unicode Transformation Format) 是一种针对 Unicode 的可变长度字符编码,又称万国码。建议在实际开发中使用 UTF-8 。

在之前的讲解中也介绍过相关的内容,比如:

javac 命令使用的 -encoding 选项值需要和 .java 源代码文件的编码方式一致;

在演示 FileInputStream 和 FileOutputStream 读取、输出文件内容时介绍过使用 UTF-8 编码、解码字符串。

2、字符编码演示

英文编码

 byte[] buf = null;
String line = ""; line = "a-b-c-d"; // 使用getBytes()方法
buf = line.getBytes();
System.out.println(Arrays.toString(buf)); System.out.println(new String(buf)); // 使用getBytes("GBK")方法
buf = line.getBytes("GBK");
System.out.println(Arrays.toString(buf)); System.out.println(new String(buf, "GBK")); // 使用getBytes("UTF-8")方法
buf = line.getBytes("UTF-8");
System.out.println(Arrays.toString(buf)); System.out.println(new String(buf, "UTF-8")); 输出: [97, 45, 98, 45, 99, 45, 100]
a-b-c-d
[97, 45, 98, 45, 99, 45, 100]
a-b-c-d
[97, 45, 98, 45, 99, 45, 100]
a-b-c-d

中文编码

 byte[] buf = null;
String line = ""; line = "测试程序-a-b-c-d"; // 使用getBytes()方法
buf = line.getBytes();
System.out.println(Arrays.toString(buf)); System.out.println(new String(buf)); // 使用getBytes("GBK")方法
// 因为GBK中中文占2个字节
// 所以全部为16个字节
buf = line.getBytes("GBK");
System.out.println(Arrays.toString(buf)); System.out.println(new String(buf, "GBK")); // 使用getBytes("UTF-8")方法
// 因为UTF-8中中文占3个字节
// 所以全部为20个字节
buf = line.getBytes("UTF-8");
System.out.println(Arrays.toString(buf)); System.out.println(new String(buf, "UTF-8"));
System.out.println(new String(buf, "GBK"));
System.out.println(new String(buf)); // 如果编码解码方式不支持中文,出来的字符串就是乱码
System.out.println(new String(buf, "ISO-8859-1")); 输出: [-78, -30, -54, -44, -77, -52, -48, -14, 45, 97, 45, 98, 45, 99, 45, 100]
测试程序-a-b-c-d
[-78, -30, -54, -44, -77, -52, -48, -14, 45, 97, 45, 98, 45, 99, 45, 100]
测试程序-a-b-c-d
[-26, -75, -117, -24, -81, -107, -25, -88, -117, -27, -70, -113, 45, 97, 45, 98, 45, 99, 45, 100]
测试程序-a-b-c-d
测试程序-a-b-c-d
测试程序-a-b-c-d
???è???¨????-a-b-c-d

3、Reader和Writer类

这两个类是字符读写的顶层类

java.io.Reader

 java.io;

 public abstract class Reader extends Object implements Readable, Closeable {}

用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。多数子类将重写此类定义的一些方法,以提供更高的读取效率。

有以下方法:

public abstract void close() throws IOException
关闭流并释放资源 public int read() throws IOException
读取单个字符。
用于高效单字符输入的子类应重写此方法 public int read(char[] cbuf) throws IOException
将字符读入数组。
返回读取的字符数,如果已到达流的末尾,则返回-1 public abstract int read(char[] cbuf, int off, int len) throws IOException
将字符读入数组的某一部分

java.io.Writer

 java.io;

 public abstract class Writer extends Object implements Appendable, Closeable, Flushable {}

写入字符流的抽象类。子类必须实现的方法仅有 write(char[], int, int)flush()和close()。多数子类将重写此类定义的一些方法,以提供更高的输出效率。

有以下方法:

public Writer append(char c) throws IOException
将指定字符输出到writer public Writer append(CharSequence csq) throws IOException
将指定字符序列输出到writer public abstract void close() throws IOException
关闭流,但要先刷新它 public abstract void flush() throws IOException
刷新流的缓冲 public void write(char[] cbuf) throws IOException
写入字符数组 public abstract void write(char[] cbuf, int off, int len) throws IOException
写入字符数组的某一部分 public void write(int c) throws IOException
写入单个字符 public void write(String str) throws IOException
写入字符串 public void write(String str, int off, int len) throws IOException
写入字符串的某一部分

4、InputStreamReader和OutputStreamWriter

InputStreamReader 类 是字节流通向字符流的桥梁:使用指定的 charset 读取字节并将其解码为字符。

每次调用 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。

为了提高效率,可以考虑在 BufferedReader 内包装 InputStreamReader。例如:

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

OutputStreamWriter 类 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。

为了提高效率,可以考虑将 OutputStreamWriter 包装到 BufferedWriter 中。例如:

Writer out = new BufferedWriter(new OutputStreamWriter(System.out));

5、缓冲字符流BufferedReader和BufferedWriter

BufferedWriter 类 将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

可以指定缓冲区的大小,或者使用默认的大小。在大多数情况下,默认值就足够大了。

该类提供了 newLine() 方法,使用平台的行分隔符概念,此概念由系统属性 line.separator 定义。

建议用 BufferedWriter 包装所有开销很高的 Writer(如 FileWriters 和 OutputStreamWriters)。

例如:PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));

将缓冲 PrintWriter 对文件的输出。如果没有缓冲,则每次调用 print() 方法会导致将字符转换为字节,然后立即写入到文件,而这是极其低效的。

BufferedReader 类 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

可以指定缓冲区的大小,或者使用默认的大小。大多数情况下,默认值就足够大了。

建议用 BufferedReader 包装所有开销很高的 Reader(如 FileReader 和 InputStreamReader)。

例如:BufferedReader in = new BufferedReader(new FileReader("foo.in"));

如果没有缓冲,则每次调用 read() 或 readLine() 都会导致从文件中读取字节,并将其转换为字符后返回,而这是极其低效的。

6、使用BufferedReader解析properties文件

 /**
* 演示使用BufferedReader解析Properties文件
*
* @author 创建人:
* @version 创建于:
*/
public class MyProperties extends Hashtable<String, String> { private static final long serialVersionUID = -90168270642387525L; /**
* 根据指定的key获取value
*
* @author 创建人:
* @version 创建于:
* @param key
* - 键
* @return value - 字符串类型的值
*/
public String getProperty(String key) {
return super.get(key);
} /**
* 根据指定的key获取value
*
* @author 创建人:
* @version 创建于:
* @param key
* - 键
* @param defaultValue
* - 默认值
* @return value - 字符串类型的值
*/
public String getProperty(String key, String defaultValue) {
String val = super.get(key);
// 如果不存在这样的键值,则返回默认值
return val == null ? defaultValue : val;
} /**
* 把proprtties打印到指定的输出流
*
* @author 创建人:
* @version 创建于:
* @param out
* - 输出流
*/
public void list(PrintWriter out) {
// 获取键集
Set<String> keys = this.stringPropertyNames();
// 遍历,输出
for (String key : keys) {
String val = this.getProperty(key, "");
out.println(key + " = " + val);
}
out.flush();
// 关闭输出流
out.close();
} /**
* 从指定的文件输入流加载properties
*
* @author 创建人:
* @version 创建于:
* @param inStream
* - 文件输入流
*/
public void load(InputStream inStream) {
InputStreamReader reader = null;
try {
// 创建Reader后调用load(Reader)方法
reader = new InputStreamReader(inStream, "UTF-8");
this.load(reader);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
if (inStream != null) {
inStream.close();
}
} catch (IOException e) {
}
}
} /**
* 从指定的字符输入流加载properties
*
* @author 创建人:
* @version 创建于:
* @param reader
* - 字符输入流
*/
public void load(Reader reader) {
BufferedReader br = null;
try {
// 创建BufferedReader
br = new BufferedReader(reader); String line = null;
// 读文件
while ((line = br.readLine()) != null) { // 去除#注释后去除前后空白
line = line.replaceAll("#.*", "").trim(); // 如果是空白行直接跳过
if (line.length() == 0) {
continue;
} // 使用\\s*=\\s*切割这行字符串
String[] keyAndValue = line.split("\\s*=\\s*"); // 如果数组长度为0直接跳过
if (keyAndValue.length == 0) {
continue;
} if (keyAndValue.length == 1) {
super.put(keyAndValue[0], null);
}
if (keyAndValue.length > 1) {
super.put(keyAndValue[0], keyAndValue[1]);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
}
} catch (IOException e) {
}
}
} /**
* 添加一个property
*
* @author 创建人:
* @version 创建于:
* @param key
* - 键
* @param value
* - 值
* @return 返回旧的值
*/
public Object setProperty(String key, String value) {
return super.put(key, value);
} /**
* 获取键的集合
*
* @author 创建人:
* @version 创建于:
* @return
*/
public Set<String> stringPropertyNames() {
return super.keySet();
} public static void main(String[] args) {
MyProperties prop = new MyProperties();
prop.load(MyProperties.class.getClassLoader().getResourceAsStream("logging.properties"));
PrintWriter out = new PrintWriter(System.out);
prop.list(out);
}
}

Java文件字符流的更多相关文章

  1. Java:文件字符流和字节流的输入和输出

    最近在学习Java,所以就总结一篇文件字节流和字符流的输入和输出. 总的来说,IO流分类如下: 输入输出方向:     输入流(从外设读取到内存)和输出流(从内存输出到外设) 数据的操作方式: 字节流 ...

  2. Java Io 字符流

    Java Io 字符流包含: 1. InputStreamReader  它是由byte流解析为char流,并且按照给定的编码解析. 2. OutputStreamWrite  它是char流到byt ...

  3. Java - 文件(IO流)

    Java - 文件 (IO)   流的分类:     > 文件流:FileInputStream | FileOutputStream | FileReader | FileWriter     ...

  4. 理解Java中字符流与字节流

    1. 什么是流 Java中的流是对字节序列的抽象,我们可以想象有一个水管,只不过现在流动在水管中的不再是水,而是字节序列.和水流一样,Java中的流也具有一个"流动的方向",通常可 ...

  5. 理解Java中字符流与字节流的区别(转)

    1. 什么是流 Java中的流是对字节序列的抽象,我们可以想象有一个水管,只不过现在流动在水管中的不再是水,而是字节序列.和水流一样,Java中的流也具有一个“流动的方向”,通常可以从中读入一个字节序 ...

  6. io流(文件字符流(FileReader,FileWriter文件的复制))

    文件字符流(FileReader,FileWriter文件的复制) 文件的复制 效率低的方法 注意:字符流需要刷新操作,字节流不需要,只有刷新后才可以将程序中的内容导入到目标文件中 package c ...

  7. 08 IO流(五)——文件字符流FileWriter/FileReader

    对比文件字节流的优势 对于文本文件的数据传输,使用文件字符流,就不用考虑编码转码的问题. 对比文件字节流,在方法上的不同有哪些 文件字符流有append方法: Writer append(char c ...

  8. Java IO: 字符流的Buffered和Filter

    作者: Jakob Jenkov  译者: 李璟(jlee381344197@gmail.com) 本章节将简要介绍缓冲与过滤相关的reader和writer,主要涉及BufferedReader.B ...

  9. Java IO: 字符流的Piped和CharArray

    作者: Jakob Jenkov 译者: 李璟(jlee381344197@gmail.com) 本章节将简要介绍管道与字符数组相关的reader和writer,主要涉及PipedReader.Pip ...

随机推荐

  1. 利用detours写了一个工具用于instrument任意指定dll的任意指定函数入口

    目录 wiki Disas Dtest Simple withdll load一个dll到指定进程 tracebld显示相关进程涉及的文件读写操作 My Instrumentation tool: w ...

  2. centos7.6下的python3.6.9虚拟环境安装elastalert

    centos7.6安装python3.6.9+elastalert .编译安装python3..9环境 # 安装依赖 yum -y install zlib-devel bzip2-devel ope ...

  3. 强化学习——如何提升样本效率 ( DeepMind 综述深度强化学习:智能体和人类相似度竟然如此高!)

    强化学习     如何提升样本效率 参考文章: https://news.html5.qq.com/article?ch=901201&tabId=0&tagId=0&docI ...

  4. CefSharp在高DPI的屏幕上出现黑边(winform)

    目录 问题现象 解决办法 1.将cefsharp的gpu设置为无效,(后遗症,h5动画会出现卡顿现象,慎用) 2.将屏幕的DPI置为96(缩放比例为100%)(后遗症,不可能每个电脑都去配置) 3.支 ...

  5. [LeetCode] 261. Graph Valid Tree 图是否是树

    Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), ...

  6. 转载:Python Web开发最难懂的WSGI协议,到底包含哪些内容?

    原文:PSC推出的第二篇文章-<Python Web开发最难懂的WSGI协议,到底包含哪些内容?>-2017.9.27 我想大部分Python开发者最先接触到的方向是WEB方向(因为总是有 ...

  7. radio和checkbox的js勾选使用

    Html: <table> <tr><th class="w1">党内职务</th><td colspan="3&q ...

  8. centos 如何修改docker镜像和容器的默认存放路径

    原因:通过df -h查看磁盘利用的时候,目前挂载的太小了,所以尝试挂载到其他地方 1 先看看默认存放的路径在哪儿 方法1:docker info 方法2:sudo docker info | grep ...

  9. IDEA 2019 注册码

     CATF44LT7C-eyJsaWNlbnNlSWQiOiJDQVRGNDRMVDdDIiwibGljZW5zZWVOYW1lIjoiVmxhZGlzbGF2IEtvdmFsZW5rbyIsImFz ...

  10. Javaweb的概念与C/S、B/S体系结构

    大家好,乐字节的小乐又来了,今天的文章是接上次<客户端请求服务器端通信, Web 编程发展基础|乐字节>,这次是讲述Javaweb的介绍和C/S.B/S体系结构. 一.Javaweb的概念 ...