在Java中,使用InputStream.read()返回的int调用Character.isXxx()方法安全吗?
在读取文本文件时,我希望执行以下操作:在Java中,使用InputStream.read()返回的int调用Character.isXxx()方法安全吗?,java,unicode,character,inputstream,Java,Unicode,Character,Inputstream,在读取文本文件时,我希望执行以下操作: InputStream input = ...; int read = input.read(); if (Character.isWhitespace(read)) { // do something with the whitespace } 另一种方法是检查负read()返回值(aka,输入结束)并显式强制转换: InputStream input = ...; int read = input.read(); if (read >=
InputStream input = ...;
int read = input.read();
if (Character.isWhitespace(read)) {
// do something with the whitespace
}
另一种方法是检查负read()
返回值(aka,输入结束)并显式强制转换:
InputStream input = ...;
int read = input.read();
if (read >= 0 && Character.isWhitespace((char) read)) {
// do something with the whitespace
}
然而,这涉及到一个额外的分支和强制转换,我希望我的代码尽可能高效,所以我更喜欢第一种方法
然而,我更希望我的代码更加健壮:),我不确定第一种方法是否会产生微妙的问题。根据我收集的信息,Unicode将0xFFFF
和0xffffff
定义为非字符,因此我认为它是安全的。但是专家们怎么说呢
为了确保这一点,问题涉及到我的方法是否对所有
Character.isXxx()
方法安全,而不仅仅是Character.isWhitespace()
是的,它是安全的。对于0xffffff
情况,所有isXxx方法都返回false。实际上,这对于0x000FFFFF
之外的所有内容都是正确的,因为这些值在Unicode中是未定义的。对于0xFFFF
来说基本上是一样的,尽管isBmpCodePoint
是正确的。方法InputStream.read()
读取单个8位字节并将其作为0x00-0xFF
范围内的32位int
返回,或者在EOF上返回-1
接受32位int
作为输入的Character.isXXX()
方法需要0x00-0x10FFFF
范围内的完整Unicode码点。如果文件由7位ASCII字符组成(其中字节0x00-0x7F
映射到代码点U+0000-U+007F
),或者ISO-8859-1(其中字节0x00-0xFF
映射到代码点U+0000-U+00FF
),则单个字节可以表示完整的代码点。如果文件使用的是任何其他编码,则无法保证任何给定字节都会按原样映射到具有相同值的代码点,特别是如果字节大于0x7F
(大多数7/8位编码使用相同的字节值以实现ASCII兼容性,但并非所有字节都这样做!)
接受16位Character
作为输入的Character.isXXX()
方法需要0x00-0xFFFF
范围内的UTF-16编码单元。单个char
可以保存一个Unicode码点,最多可保存一个码点U+FFFF
。但是,这些方法不支持UTF-16代理,因此无法处理U+FFFF
以上的Unicode代码点(需要2个char
值来表示它们)
因此,为了回答您的问题,您能否
读取()文件中的任何给定字节,并将其原样传递给Character.isXXX()
方法并获得可靠的结果?答案是-它取决于文件的实际编码。如果文件以7位ASCII或8位ISO-8859-1编码,则为是。否则,可能是这样,但通常仅适用于字节0x7F,因为字节0x80-0xFF
是特定于编码的,并且取决于特定编码在字节和Unicode码点之间的映射方式(假设文件开始时甚至使用7/8位编码)。read()的-1返回值`是带外值,不应用于检测流结束以外的任何目的。我刚刚意识到我的问题实际上相当愚蠢,使用InputStream
s读取文本。。。当然,我应该使用阅读器
。如果是这样,安全吗?我想是的,因为这就归结为Character.isXxx(int)方法是否会为-1
返回
false`的问题,它们确实返回了(我通过实验验证了这一点)。是的,在读取文本文件时,应该使用基于字符的API,例如InputStreamReader
,而不是基于字节的API。但是,为了成功地使用这样的读取器,您必须提前知道输入的编码,以便可以在构造函数中指定该字符集。如果输入有一个用于指定字符集的BOM表,那么您必须首先自己阅读BOM表,因为不幸的是,Java通常不会为您处理BOM表。