返回
摘自微电脑世界

Java语言中字符的处理

山西省网络管理中心 任 军

  摘 要: 本 文 主 要 讨 论 了Java 语 言 中 字 符 的 特 殊 表 达 形 式, 尤 其 是 中 文 信 息 的 表 达 处 理, 阐 述 了 字 符 处 理 的 关 键 是 要 将 十 六 位Unicode 字 符, 转 换 为 本 地 下 层 平 台, 也 就 是 运 行Java 虚 拟 处 理 机 的 平 台 能 够 理 解 的 字 符 形 式。

  关 键 词:Java、 字 符、8 位、16 位、Unicode 字 符 集

  Java 是 一 种 编 程 语 言、 一 个 运 行 系 统、 一 套 开 发 工 具 和 一 个 应 用 程 序 编 程 界 面(API)。Java 建 立 在C++ 的 熟 悉、 有 用 的 特 征 之 上, 而 取 消 了C++ 的 复 杂 的、 危 险 的 和 多 余 的 元 素。 它 是 一 个 更 安 全、 更 简 单、 更 容 易 使 用 的 语 言。

1、Java 的 字 符 表 达

  Java 语 言 和C 语 言 对 字 符 进 行 了 互 不 相 同 的 描 述,Java 使 用16 位 的Unicode 字 符 集( 该 标 准 描 述 了 许 多 语 言 的 各 种 不 同 字 符), 因 此Java 字 符 是 一 个16 位 的 无 符 号 整 数, 字 符 变 量 用 来 存 放 单 个 字 符, 而 不 是 完 整 的 字 符 串。

  一 个 字 符(character) , 就 是 单 个 字 母(letter), 许 多 字 母 构 成 一 个 单 词, 一 组 单 词 组 成 句 子, 以 此 类 推。 但 是 对 于 含 有 诸 如 中 文 信 息 的 字 符, 就 不 是 那 么 简 单 了。

  Java 的 基 本 的char 类 型 被 定 义 成 无 符 号 的16 位, 它 是Java 中 唯 一 的 一 个 无 符 号 类 型。 使 用16 位 表 达 字 符 的 主 要 原 因 是 要 让Java 能 够 支 持 任 何Unicode 字 符, 因 此 而 使 得Java 适 用 于 描 述 或 显 示 任 何 被Unicode 支 持 的 语 言, 可 移 植 性 也 就 会 更 好。 但 是, 能 够 支 持 某 种 语 言 的 字 符 串 显 示, 和 能 够 正 确 打 印 某 种 语 言 的 字 符 串, 常 常 是 两 个 不 同 的 问 题。 由 于Oak(Java 最 初 的 代 号) 开 发 组 的 主 要 环 境 是Unix 系 统 和 某 些 源 于Unix 的 系 统, 所 以 对 开 发 人 员 来 说, 最 为 方 便 实 用 的 字 符 集 是ISO Latin-1。 相 应 地, 这 一 开 发 组 就 带 有Unix 遗 传 性, 也 就 导 致 了Java 的I/O 系 统 在 很 大 程 度 上 以Unix 的 流 概 念 为 模 型, 而 在Unix 系 统 中, 每 一 种I/O 设 备 都 是 用 一 串8 比 特 的 流 来 表 示。 这 种 在I/O 系 统 方 面 取 模 于Unix 的 做 法, 使 得Java 语 言 拥 有16 位 的Java 字 符, 而 却 只 有8 位 的 输 入 设 备, 这 样 就 给Java 带 来 了 些 不 足。 因 此 在 任 何 一 处Java 字 符 串 按8 位 来 读 入 或 写 出 的 地 方, 都 得 有 一 小 段 程 序 代 码, 被 称 为" 劈(hack)", 来 将8 位 的 字 符 映 射 成 为16 位Unicode, 或 将16 位 的Unicode 劈 成8 位 字 符。

2、 问 题 及 解 决

  我 们 要 实 现 从 一 个 文 件 读 取 信 息, 尤 其 是 读 取 含 有 中 文 信 息 的 文 件, 并 将 读 取 到 的 信 息 显 示 在 屏 幕 上, 一 般 我 们 使 用FileInputStream 函 数 打 开 文 件、readChar 函 数 读 入 字 符。 如 下:

import java.io.*;

public class rf{

public static void main(String args[]) {

FileInputStream fis;

DataInputStream dis;

char c;

try {

fis = new FileInputStream("xinxi.txt");

dis = new DataInputStream(fis);

while (true) {

c = dis.readChar();

System.out.print(c);

System.out.flush();

if (c == '\n') break;

}

fis.close();

} catch (Exception e) { }

System.exit(0);

}

}

  但 是 事 实 上, 运 行 这 一 程 序, 所 能 得 到 的 输 出 结 果 是 一 堆 无 用 的 乱 码。 不 能 正 确 输 出xinxi.txt 文 件 内 容, 其 原 因 是readChar 函 数 读 入 的 是16 位 的Unicode 字 符, 而System.out.print 却 将 其 当 作 八 位 的ISO latin-1 字 符 输 出。

  Java 1.1 版 本 引 入 了 一 套 全 新 的Readers 和Writers 接 口 来 处 理 字 符。 我 们 可 以 利 用InputStreamReader 类 而 不 是DataInputStream 来 处 理 文 件。 修 改 上 面 的 程 序 如 下:

import java.io.*;

public class rf {

public static void main(String args[]) {

FileInputStream fis;

InputStreamReader irs;

char ch;

try {

fis = new FileInputStream("xinxi.txt");

irs = new InputStreamReader(fis);

while (true) {

ch = (char) irs.read();

System.out.print(c);

System.out.flush();

if (ch == '\n') break;

}

fis.close();

} catch (Exception e) { }

System.exit(0);

}

}

  这 样 才 能 正 确 输 出xinxi.txt 中 的 文 本( 尤 其 是 中 文 信 息)。 另 外, 当xinxi.txt 文 件 来 自 不 同 的 机 器, 即 来 自 不 同 操 作 平 台( 或 汉 字 内 码 不 同) 的 机 器, 比 如: 文 件 来 自 客 户 端( 客 户 端 上 传 文 件 给 服 务 器), 而 读 取 文 中 信 息 的 操 作 由 服 务 器 端 执 行。 如 果 用 上 面 的 程 序 来 实 现 这 一 功 能, 就 有 可 能 仍 然 不 能 得 到 正 确 的 结 果。 其 原 因 就 是 输 入 编 码 转 换 失 败, 我 们 还 需 要 进 行 如 下 的 改 动:

......

    int c1;

int j=0;

    StringBuffer str=new StringBuffer();

    char lll[][]= new char[20][500];

    String ll="";

try {

fis = new FileInputStream("fname.txt");

irs = new InputStreamReader(fis);

    c1=irs.read(lll[1],0,50);

while (lll[1][j]!=' ') {

str.append(lll[1][j]);

j=j+1;

}

        ll=str.toString();

System.out.println(ll);

} catch (IOException e) {

System.out.println(e.toString());}

    ......

  这 样, 输 出 的 结 果 就 正 确 了。 当 然, 上 面 的 程 序 是 不 完 整 的, 只 是 说 明 了 一 下 解 决 的 方 法。

  总 之,Java 语 言 中 字 符 处 理, 尤 其 是 中 文 信 息 的 处 理, 比 较 特 殊。 在Java 中, 字 符 处 理 的 关 键 是 要 将 十 六 位Unicode 字 符, 转 换 为 本 地 下 层 平 台 也 就 是 运 行Java 虚 拟 处 理 机 的 平 台 能 够 理 解 的 字 符 形 式。