2012-07-03 34 views
7

Các mã sauLỗi Java? Tại sao thêm 0 byte trong mã hóa utf8?

public class CharsetProblem { 
public static void main(String[] args) { 
    //String str = "aaaaaaaaa"; 
    String str = "aaaaaaaaaa"; 
    Charset cs1 = Charset.forName("ASCII"); 
    Charset cs2 = Charset.forName("utf8"); 

    System.out.println(toHex(cs1.encode(str).array())); 
    System.out.println(toHex(cs2.encode(str).array())); 

} 

public static String toHex(byte[] outputBytes) { 

    StringBuilder builder = new StringBuilder(); 

    for(int i=0; i<outputBytes.length; ++i) { 
     builder.append(String.format("%02x", outputBytes[i])); 
    } 

    return builder.toString(); 
} 
} 

lợi nhuận

61616161616161616161 
6161616161616161616100 

ví dụ: utf8 mã hóa trả về byte dư thừa. Nếu chúng tôi mất ít hơn một s, sau đó chúng tôi sẽ không có byte dư thừa. Nếu chúng ta lấy thêm a-s, chúng ta có thể nhận được nhiều byte dư thừa hơn.

Tại sao?

Làm cách nào để giải quyết vấn đề này?

Trả lời

6

Bạn không thể lấy mảng sao lưu và sử dụng nó. ByteBuffers có capacity, position and a limit.

System.out.println(cs1.encode(str).remaining()); 
System.out.println(cs2.encode(str).remaining()); 

sản xuất:

10 
10 

Hãy thử điều này thay vì:

public static void main(String[] args) { 
    //String str = "aaaaaaaaa"; 
    String str = "aaaaaaaaaa"; 
    Charset cs1 = Charset.forName("ASCII"); 
    Charset cs2 = Charset.forName("utf8"); 

    System.out.println(toHex(cs1.encode(str))); 
    System.out.println(toHex(cs2.encode(str))); 
} 

public static String toHex(ByteBuffer buff) { 
    StringBuilder builder = new StringBuilder(); 
    while (buff.remaining() > 0) { 
    builder.append(String.format("%02x", buff.get())); 
    } 
    return builder.toString(); 
} 

Nó tạo ra sự mong đợi:

61616161616161616161 
61616161616161616161 
6

Bạn giả định rằng mảng sao lưu cho ByteBuffer chính xác là kích thước chính xác để giữ nội dung, nhưng không nhất thiết phải. Trong thực tế, nội dung thậm chí không cần phải bắt đầu ở byte đầu tiên của mảng! Nghiên cứu API cho ByteBuffer và bạn sẽ hiểu điều gì đang xảy ra: nội dung bắt đầu ở giá trị được trả lại bởi arrayOffset() và kết thúc được trả về bởi limit().

2

Câu trả lời đã được đưa ra, nhưng khi tôi chạy vào cùng một vấn đề, tôi nghĩ nó có thể hữu ích để cung cấp thêm chi tiết:

Mảng byte được trả lại bằng cách gọi cs1.encode(str).array() hoặc cs2.encode(str).array() trả về tham chiếu đến toàn bộ mảng được phân bổ cho ByteBuffer tại thời điểm đó. Dung lượng của mảng có thể lớn hơn dung lượng thực sự được sử dụng. Để chỉ truy xuất phần được sử dụng, bạn nên làm như sau:

ByteBuffer bf1 = cs1.encode(str); 
ByteBuffer bf2 = cs2.encode(str); 
System.out.println(toHex(Arrays.copyOf(bf1.array(), bf1.limit()))); 
System.out.println(toHex(Arrays.copyOf(bf2.array(), bf2.limit()))); 

Điều này mang lại kết quả mong đợi.

Các vấn đề liên quan