在Java中将ANSI字符转换为UTF-8

4
有没有一种方法可以使用Java将ANSI字符串转换为UTF?我有一个自定义的序列化程序,使用DataInputStream类的readUTF和writeUTF方法进行反序列化和序列化串。如果我收到一个编码为ANSI且过长(约100,000个字符长)的字符串,则会出现错误;
Caused by:java.io.UTFDataFormatException: encoded string too long: 106958 bytes
但是在我的Junit测试中,我能够创建一个包含120000个'a'的字符串,并且它完美地工作。
我已经检查了以下帖子,但仍然出现错误;
- 在Java中将UTF-8转换为ISO-8859-1-如何保持单字节 - 如何替换Ruby中的重音拉丁字符?

你是否是指ASCII?如果是,它已经在UTF-8中了 - 你能再解释一下吗?展示错误等。 - mmmmmm
4
不是所有的 ANSI 都等同于 ASCII。ANSI 是一个包含多个编码页的集合。 - Aaron Digulla
由于readUTF和writeUTF的大小限制,我已经修改了我的序列化程序,将文本分段发送。 - n002213f
4个回答

6

这个错误不是由字符编码引起的。它意味着UTF数据的长度错误。

编辑:刚刚意识到这是一个写入错误,而不是读取错误。

UTF长度只有2个字节,所以它只能容纳64K UTF-8字节。您正在尝试写入100K,这是行不通的。

这个限制是硬编码的,没有办法绕过它。

if (utflen > 65535)
    throw new UTFDataFormatException(
            "encoded string too long: " + utflen + " bytes");

有趣,但是为什么我的所有带更多字符的测试都通过了? - n002213f
你必须向我展示你的测试用例。它们是错误的。请查看我的编辑。 - ZZ Coder
我使用以下代码生成测试字符串: StringBuffer sb2 = new StringBuffer(); for (int i=0; i < 120000;i++) { sb2.append("a"); } String longString2 = sb2.toString(); - n002213f
你可以创建长字符串,直到内存用尽。但是你不能使用writeUTF()来写入长字符串。你需要用4字节长度头自己编写它。 - ZZ Coder

3
byte[] asciiBytes = ...;
String unicode = new String(asciiBytes, "US-ASCII");
byte[] utfBytes = unicode.getBytes("UTF-8");

看起来我误读了关于 ASCII vs. ANSI 的原始问题,并且随着最新的问题编辑,我的答案并不是真正相关的。 - iammichael

2

使用哪个ANSI代码页?有许多不同的字符编码都称为“ANSI”。DOS代码页是437(不包括绘图符号)。如果您使用代码页850,则可以这样做:

String unicode = new String(bytes, "IBM850");

(其中bytes是一个包含ANSI字符的数组)。之后,您可以使用任何编码将此字符串转换为字节数组,例如unicode.getBytes(encoding)

Windows通常使用代码页1252(请使用“windows-1252”)。


尝试过了但是不起作用,我得到了相同的错误。有没有一种方法可以检查字符串的编码,以便我可以确定它是ANSI编码? - n002213f
这将把 Telnet 中的 ANSI 转换为“常规”字符串吗? - Thufir
这将把任何来源的字节转换为Unicode字符串。但是,为了使其正常工作,您需要确切地知道源正在使用哪种编码。无论是文件、远程服务还是硬件设备都没有关系。 - Aaron Digulla

1

ZZ Coder已经回答了这个问题,但我写了一个更详细的解释,并在这篇博客中提出了一个解决方法。基本上,问题出在DataOutputStream上,因为它将可写字符串限制为64KB。还有其他可能的解决方法可以绕过这个问题,其中一些可能可以在不破坏实际使用的二进制数据格式的情况下工作...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接