在Java中,使用从InputStream.read()返回的int调用Character.isXxx()方法是否安全?

时间:2015-03-01 15:18:08

标签: java unicode character inputstream

在阅读文本文件时,我想做这样的事情:

InputStream input = ...;
int read = input.read();
if (Character.isWhitespace(read)) {
    // do something with the whitespace
}

另一种方法是检查负read()返回值(也就是输入结束)并显式转换:

InputStream input = ...;
int read = input.read();
if (read >= 0 && Character.isWhitespace((char) read)) {
    // do something with the whitespace
}

然而,这涉及额外的分支和演员,我希望我的代码尽可能高效,所以我更喜欢第一种方法。

但是,我希望我的代码更强大:)我不确定第一种方法是否会产生微妙的问题。根据我收集的内容,Unicode将0xFFFF0xFFFFFFFF定义为非字符,因此我认为它是安全的。但专家们说了什么?

只是为了确保,问题与我的方法是否对所有 Character.isXxx()方法都安全有关,而不仅仅是Character.isWhitespace()

2 个答案:

答案 0 :(得分:2)

InputStream.read()方法读取单个8位字节并将其作为int范围内的32位0x00 - 0xFF返回,或者返回{ EOF上的{1}}。

接受32位-1作为输入的Character.isXXX()方法需要{strong>完整的Unicode代码点,范围为int。如果文件由7位ASCII字符组成(其中字节0x00 - 0x10FFFF映射到代码点0x00 - 0x7F)或ISO-,则单个字节可以按原样表示完整代码点8859-1(其中字节U+0000 - U+007F映射到代码点0x00 - 0xFF)。如果文件使用任何其他编码,则无法保证任何给定字节将按原样映射到具有相同值的代码点,尤其是当字节大于U+0000 - U+00FF时(大多数7/8位编码使用相同的字节值进行ASCII兼容 - 但不是全部都这样做。)。

接受16位0x7F作为输入的Character.isXXX()方法需要{strong> UTF-16代码单元,范围为char。单个0x00 - 0xFFFF可以保存Unicode代码点,直到代码点char。但是,这些方法不支持支持UTF-16代理,因此无法处理U+FFFF上方的Unicode代码点(需要2 U+FFFF个值来代表它们)。

因此,要回答您的问题 - 您可以char来自文件的任何给定字节并将其原样传递给read()方法并获得可靠的结果吗?答案是 - 取决于文件的实际编码。如果文件是以7位ASCII或8位ISO-8859-1编码,那么是。否则,可能是,但通常仅用于字节0x7F,因为字节Character.isXXX()是特定于编码的,并且将取决于特定编码如何在字节和Unicode代码点之间映射(假设文件甚至使用一个7/8位编码开始)。

答案 1 :(得分:0)

是的,这很安全。对于0xFFFFFFFF情况,所有isXxx方法都返回false。实际上,对于0x000FFFFF之外的所有内容都是如此,因为这些值在Unicode中是未定义的。对于0xFFFF,它大致相同,尽管isBmpCodePoint是真的。