Java 中的 FileInputStream 和 Unicode
FileInputStream and Unicode in Java
我是新手Java,我尝试了解字节流和字符流,我看到很多人说字节流只适用于ASCII字符集,而字符流可以支持所有类型字符集ASCII,Unicode等。我认为有一个误解,因为我可以使用byte strem来读写一个Unicode字符。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class DemoApp {
public static void main(String args[]) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("abc.txt");
fos = new FileOutputStream("def.txt");
int k;
while ((k = fis.read()) != -1) {
fos.write(k);
System.out.print((char) k);
}
}
catch (FileNotFoundException fnfe) {
System.out.printf("ERROR: %s", fnfe);
}
catch (IOException ioe) {
System.out.printf("ERROR: %s", ioe);
}
finally {
try {
if (fos != null)
fos.close();
}
catch (IOException ioe) {
System.out.printf("ERROR: %s", ioe);
}
try {
if (fis != null)
fis.close();
}
catch (IOException ioe) {
System.out.printf("ERROR: %s", ioe);
}
}
}
}
abc.txt 文件包含 Unicode 字符 Ǽ,我使用 UTF-8 编码保存文件。代码运行良好,它创建了一个新文件 def.txt 并且该文件包含 Unicode 字符 Ǽ.
我有两个问题:
字节流关于Unicode字符的真相是什么?字节流是否支持Unicode字符?
当我尝试使用 s.o.p((char) k) 打印时,结果不是 Unicode 字符,它只是 ASCII 字符:Ǽ。而且我不明白为什么结果不是 Unicode 字符,因为我知道 Java 和 char 数据类型支持 Unicode 字符。我尝试将此代码保存为 UTF-8,但问题仍然存在。
对不起我的英语语法,提前谢谢你!
What is the truth about byte stream regarding Unicode character? Does byte stream support Unicode character or not?
事实上,没有 "Unicode character" 这样的东西。您不应混淆三个不同的概念。
- Unicode 代码点
- 代码点序列的某种编码中的字符。
- Java
char
类型,两者都不是。严格来说。
你需要认真阅读一下背景资料:
- Unicode 上的维基百科页面
- https://www.w3.org/International/talks/0505-unicode-intro/
- https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/
弄清这一点后,我们可以说虽然字节流可用于读取 Unicode 代码点 [=57] 序列的 编码 =],流 API 设计不是为了读写任何形式的基于字符的文本而设计的。它是为读取和写入字节序列(8 位二进制值)而设计的……它可以代表任何东西。 Stream API 被设计成不知道字节代表什么:它不知道,也不关心!
When I try to print with s.o.p((char) k) the result is not an Unicode character, it is just ASCII character: Ǽ. And I don't understand why the result is not an Unicode character because I know that Java and char data type support Unicode character. I tried to save this code as UTF-8 but the problem persists.
(更正。这些不是 ASCII 字符,它们是 LATIN-1 字符!)
问题不在Java。问题是控制台被配置为期望文本以特定的字符编码发送给它,但您发送的字符使用不同的编码。
当您使用流读取和写入字符时,流不知道也不关心编码。因此,如果您读取一个有效的 UTF-8 编码文本文件并使用流将其写入期望(例如)LATIN-1 的控制台,那么结果通常是垃圾。
另一种获取垃圾的方法(这就是这里发生的事情)是将编码文件读取为字节序列,然后将字节转换为字符并打印字符。那是错误的做法。如果要字符正确输出,需要将字节解码成字符序列,然后打印字符。转换不是解码。
如果您通过 Reader 读取字节,解码会自动进行,您不会得到那种重整。 (您可能会得到另一种......如果控制台无法显示字符,或者如果您配置 Reader 堆栈以使用错误的字符集解码。)
总结:如果您正在尝试制作文件的文字副本(例如),请使用字节流。如果您尝试将文件作为文本处理,请使用字符流。
您的示例代码的问题在于,您似乎试图通过一次遍历文件同时执行这两项操作;即制作文件的文字副本并将其显示为控制台上的文本。这在技术上是可行的……但很难。我的建议:不要试图同时做这两件事。
我是新手Java,我尝试了解字节流和字符流,我看到很多人说字节流只适用于ASCII字符集,而字符流可以支持所有类型字符集ASCII,Unicode等。我认为有一个误解,因为我可以使用byte strem来读写一个Unicode字符。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class DemoApp {
public static void main(String args[]) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("abc.txt");
fos = new FileOutputStream("def.txt");
int k;
while ((k = fis.read()) != -1) {
fos.write(k);
System.out.print((char) k);
}
}
catch (FileNotFoundException fnfe) {
System.out.printf("ERROR: %s", fnfe);
}
catch (IOException ioe) {
System.out.printf("ERROR: %s", ioe);
}
finally {
try {
if (fos != null)
fos.close();
}
catch (IOException ioe) {
System.out.printf("ERROR: %s", ioe);
}
try {
if (fis != null)
fis.close();
}
catch (IOException ioe) {
System.out.printf("ERROR: %s", ioe);
}
}
}
}
abc.txt 文件包含 Unicode 字符 Ǽ,我使用 UTF-8 编码保存文件。代码运行良好,它创建了一个新文件 def.txt 并且该文件包含 Unicode 字符 Ǽ.
我有两个问题:
字节流关于Unicode字符的真相是什么?字节流是否支持Unicode字符?
当我尝试使用 s.o.p((char) k) 打印时,结果不是 Unicode 字符,它只是 ASCII 字符:Ǽ。而且我不明白为什么结果不是 Unicode 字符,因为我知道 Java 和 char 数据类型支持 Unicode 字符。我尝试将此代码保存为 UTF-8,但问题仍然存在。
对不起我的英语语法,提前谢谢你!
What is the truth about byte stream regarding Unicode character? Does byte stream support Unicode character or not?
事实上,没有 "Unicode character" 这样的东西。您不应混淆三个不同的概念。
- Unicode 代码点
- 代码点序列的某种编码中的字符。
- Java
char
类型,两者都不是。严格来说。
你需要认真阅读一下背景资料:
- Unicode 上的维基百科页面
- https://www.w3.org/International/talks/0505-unicode-intro/
- https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/
弄清这一点后,我们可以说虽然字节流可用于读取 Unicode 代码点 [=57] 序列的 编码 =],流 API 设计不是为了读写任何形式的基于字符的文本而设计的。它是为读取和写入字节序列(8 位二进制值)而设计的……它可以代表任何东西。 Stream API 被设计成不知道字节代表什么:它不知道,也不关心!
When I try to print with s.o.p((char) k) the result is not an Unicode character, it is just ASCII character: Ǽ. And I don't understand why the result is not an Unicode character because I know that Java and char data type support Unicode character. I tried to save this code as UTF-8 but the problem persists.
(更正。这些不是 ASCII 字符,它们是 LATIN-1 字符!)
问题不在Java。问题是控制台被配置为期望文本以特定的字符编码发送给它,但您发送的字符使用不同的编码。
当您使用流读取和写入字符时,流不知道也不关心编码。因此,如果您读取一个有效的 UTF-8 编码文本文件并使用流将其写入期望(例如)LATIN-1 的控制台,那么结果通常是垃圾。
另一种获取垃圾的方法(这就是这里发生的事情)是将编码文件读取为字节序列,然后将字节转换为字符并打印字符。那是错误的做法。如果要字符正确输出,需要将字节解码成字符序列,然后打印字符。转换不是解码。
如果您通过 Reader 读取字节,解码会自动进行,您不会得到那种重整。 (您可能会得到另一种......如果控制台无法显示字符,或者如果您配置 Reader 堆栈以使用错误的字符集解码。)
总结:如果您正在尝试制作文件的文字副本(例如),请使用字节流。如果您尝试将文件作为文本处理,请使用字符流。
您的示例代码的问题在于,您似乎试图通过一次遍历文件同时执行这两项操作;即制作文件的文字副本并将其显示为控制台上的文本。这在技术上是可行的……但很难。我的建议:不要试图同时做这两件事。