我已经创建了一个Android应用,实际上一切正常。
我通过websockets从服务器获取数据但在将其发送到客户端之前,它在服务器上使用GZIPOutputStream
压缩,如下所示:
public class GZip {
public static ByteBuffer compress(String msg) {
if(msg == null || msg.length() == 0)
return null;
ByteBuffer bytes = null;
try {
ByteArrayOutputStream obj=new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(obj);
gzip.write(msg.getBytes("UTF-8"));
gzip.close();
bytes = ByteBuffer.wrap(obj.toByteArray());
} catch(Exception e) {
return null;
}
return bytes;
}
}
在客户端(Android应用),String msg
解压缩:
private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
public static String decompress(byte[] compressed) {
String msg = null;
try {
final int BUFFER_SIZE = 32;
ByteArrayInputStream is = new ByteArrayInputStream(compressed);
GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE);
StringBuilder string = new StringBuilder();
byte[] data = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = gis.read(data)) != -1) {
string.append(new String(data, 0, bytesRead, UTF8_CHARSET));
}
gis.close();
is.close();
msg = string.toString();
} catch (Exception e) {
e.printStackTrace();
}
return msg;
}
因此,根据我的理解,在处理非US-ASCII字符时不会产生任何问题,因为所有内容都在UTF-8中正确解码或解码。
例如,考虑包含特殊字符Eckstoß
的单词ß
。以下是Android应用中三个TextViews
的示例,它们都显示单词Eckstoß
我觉得这里很奇怪的是,Exkstoß
这个词的所有三个版本都是如上所述进行/解码的。但是,在一行中它显示不正确。
然而,它甚至变成(恕我直言)weireder。这实际上是一个列表视图,当(由于滚动)TextView
消失并重新出现时(例如再次缩小),然后(有时)正确显示字符。
什么可能导致这个奇怪的问题?
答案 0 :(得分:0)
这只是猜测。
您以32字节为单位读取解压缩的字节,然后使用此代码段从字节转换为utf8字符:
new String(data, 0, bytesRead, UTF8_CHARSET)
问题可能是data
中的32个字节与字符边界不对齐吗?即特殊字符用两个或多个字节编码,但不是最后一个字符的所有字节都在data
缓冲区中。
这个理论并没有解释为什么滚动会给你不同的结果。
答案 1 :(得分:0)
当以UTF-8编码unicode字符时,结果字节数为1,2,3或4.例如,当日语字符U+3042以UTF-8编码时,结果字节为3(0xE3,0x81,0x82)。另一个例子是U+20BB7。当以UTF-8编码时,此unicode字符将转换为4个字节(0xF0,0xA0,0xAE,0xB7)。
假设gis.read(data)
正在尝试读取[0xF0,0xA0,0xAE,0xB7](=其unicode标量值为U + 20BB7)。是否有gis.read(data)
始终返回4的保证?例如,如果它返回2,则new String(data, 0, 2, UTF_8_CHARSET)
无法将给定的字节数组解析为有效的UTF-8序列。