2011-10-03 26 views
9

Khi tôi đang cố gắng phân tích cú pháp xml bằng cách sử dụng sax qua ổ cắm, tôi gặp phải một sự xuất hiện kỳ ​​lạ. Sau khi phân tích, tôi nhận thấy rằng DataOutputStream thêm 2 byte trước dữ liệu của tôi.Tại sao DataOutputStream.writeUTF() thêm 2 byte vào đầu?

nhắn gửi qua DataOutputStream:

0020 50 18 00 20 0f df 00 00 00 9d 3c 3f 78 6d 6c 20 P.. .... ..<?xml 
0030 76 65 72 73 69 6f 6e 3d 22 31 2e 30 22 3f 3e 3c version= "1.0"?>< 
0040 63 6f 6d 70 61 6e 79 3e 3c 73 74 61 66 66 3e 3c company> <staff>< 
0050 66 69 72 73 74 6e 61 6d 65 3e 79 6f 6e 67 3c 2f firstnam e>yong</ 
0060 66 69 72 73 74 6e 61 6d 65 3e 3c 6c 61 73 74 6e firstnam e><lastn 
0070 61 6d 65 3e 6d 6f 6f 6b 20 6b 69 6d 3c 2f 6c 61 ame>mook kim</la 
0080 73 74 6e 61 6d 65 3e 3c 6e 69 63 6b 6e 61 6d 65 stname>< nickname 
0090 3e c2 a7 3c 2f 6e 69 63 6b 6e 61 6d 65 3e 3c 73 >..</nic kname><s 
00a0 61 6c 61 72 79 3e 31 30 30 30 30 30 3c 2f 73 61 alary>10 0000</sa 
00b0 6c 61 72 79 3e 3c 2f 73 74 61 66 66 3e 3c 2f 63 lary></s taff></c 
00c0 6f 6d 70 61 6e 79 3e        ompany> 

nhắn gửi sử dụng Transformer:

0020 50 18 00 20 b6 b1 00 00 3c 3f 78 6d 6c 20 76 65 P.. .... <?xml ve 
0030 72 73 69 6f 6e 3d 22 31 2e 30 22 20 65 6e 63 6f rsion="1 .0" enco 
0040 64 69 6e 67 3d 22 75 74 66 2d 38 22 3f 3e 3c 63 ding="ut f-8"?><c 
0050 6f 6d 70 61 6e 79 3e 3c 73 74 61 66 66 3e 3c 66 ompany>< staff><f 
0060 69 72 73 74 6e 61 6d 65 3e 79 6f 6e 67 3c 2f 66 irstname >yong</f 
0070 69 72 73 74 6e 61 6d 65 3e 3c 6c 61 73 74 6e 61 irstname ><lastna 
0080 6d 65 3e 6d 6f 6f 6b 20 6b 69 6d 3c 2f 6c 61 73 me>mook kim</las 
0090 74 6e 61 6d 65 3e 3c 6e 69 63 6b 6e 61 6d 65 3e tname><n ickname> 
00a0 c2 a7 3c 2f 6e 69 63 6b 6e 61 6d 65 3e 3c 73 61 ..</nick name><sa 
00b0 6c 61 72 79 3e 31 30 30 30 30 30 3c 2f 73 61 6c lary>100 000</sal 
00c0 61 72 79 3e 3c 2f 73 74 61 66 66 3e 3c 2f 63 6f ary></st aff></co 
00d0 6d 70 61 6e 79 3e         mpany> 

Như người ta có thể nhận thấy DataOutputStream thêm hai byte ở phía trước của thông điệp. Vì vậy, trình phân tích cú pháp sax ném ngoại lệ "org.xml.sax.SAXParseException: Nội dung không được phép trong prolog.". Tuy nhiên khi tôi bỏ qua 2 byte này, trình phân tích cú pháp sax hoạt động tốt. Tôi nhận thấy rằng DataInputStream không thể đọc thông báo Biến áp.

Câu hỏi của tôi là: Tại sao DataOutputStream thêm các byte này và tại sao Trình biến đổi không?




Đối với những người quan tâm trong việc tái tạo các vấn đề ở đây là một số mã:

Server sử dụng DataInputStream:

String data = "<?xml version=\"1.0\"?><company><staff><firstname>yong</firstname><lastname>mook kim</lastname><nickname>§</nickname><salary>100000</salary></staff></company>"; 
ServerSocket server = new ServerSocket(60000); 
Socket socket = server.accept(); 
DataOutputStream os = new DataOutputStream(socket.getOutputStream()); 
os.writeUTF(data); 
os.close(); 
socket.close(); 

Server sử dụng Transformer:

ServerSocket server = new ServerSocket(60000); 
Socket socket = server.accept(); 
Document doc = createDocument(); 
printXML(doc, os); 
os.close(); 
socket.close(); 

public synchronized static void printXML(Document document, OutputStream stream) throws TransformerException 
{ 
    DOMSource domSource = new DOMSource(document); 
    StreamResult streamResult = new StreamResult(stream); 
    TransformerFactory tf = TransformerFactory.newInstance(); 
    Transformer serializer = tf.newTransformer(); 
    serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8"); 
    serializer.setOutputProperty(OutputKeys.INDENT, "no"); 
    serializer.transform(domSource, streamResult); 
} 

private static Document createDocument() throws ParserConfigurationException 
{ 
    Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 
    Element company = document.createElement("company"); 
    Element staff = document.createElement("staff"); 
    Element firstname = document.createElement("firstname"); 
    Element lastname = document.createElement("lastname"); 
    Element nickname = document.createElement("nickname"); 
    Element salary = document.createElement("salary"); 
    Text firstnameText = document.createTextNode("yong"); 
    Text lastnameText = document.createTextNode("mook kim"); 
    Text nicknameText = document.createTextNode("§"); 
    Text salaryText = document.createTextNode("100000"); 
    document.appendChild(company); 
    company.appendChild(staff); 
    staff.appendChild(firstname); 
    staff.appendChild(lastname); 
    staff.appendChild(nickname); 
    staff.appendChild(salary); 
    firstname.appendChild(firstnameText); 
    lastname.appendChild(lastnameText); 
    nickname.appendChild(nicknameText); 
    salary.appendChild(salaryText); 
    return document; 
} 


Khách hàng sử dụng SAX Parser:

SAXParserFactory factory = SAXParserFactory.newInstance(); 
SAXParser saxParser = factory.newSAXParser(); 
DefaultHandler handler = new MyHandler(); 
Socket socket = new Socket("localhost", 60000); 
InputSource is = new InputSource(new InputStreamReader(socket.getInputStream())); 
is.setEncoding("UTF-8"); 
//socket.getInputStream().skip(2); // skip over the 2 bytes from the DataInputStream 
saxParser.parse(is, handler); 

Khách hàng sử dụng DataInputStream:

Socket socket = new Socket("localhost", 60000); 
DataInputStream os = new DataInputStream(socket.getInputStream()); 
while(true) { 
    String data = os.readUTF(); 
    System.out.println("Data: " + data); 
} 
+0

Tôi không biết nếu nó làm cho một sự khác biệt, nhưng văn bản xml đầu tiên của bạn không có 'encoding = 'utf-8'. –

+0

Ngoài ra, tại sao bạn muốn sử dụng DataInputStream? Điều đó không cần thiết khi đọc XML. – StaxMan

+0

DataInputStream được sử dụng để kiểm tra vì tôi không biết rằng nó sử dụng giao thức riêng của nó. –

Trả lời

21

Kết quả của DataOutputStream.writeUTF() là một định dạng tùy chỉnh, dự định sẽ được đọc bởi DataInputStream.readUTF().

Các javadocs của phương pháp writeUTF bạn đang gọi nói:

Viết một chuỗi các dòng sản lượng tiềm ẩn sử dụng sửa đổi mã hóa UTF-8 một cách máy độc lập.

Đầu tiên, hai byte được ghi vào luồng đầu ra như thể theo phương thức writeShort cho số byte theo sau. Giá trị này là số byte thực sự được viết ra, không phải là độ dài của chuỗi. Theo chiều dài, mỗi ký tự của chuỗi là đầu ra, theo thứ tự, sử dụng mã hóa UTF-8 đã sửa đổi cho ký tự. Nếu không có ngoại lệ được ném, bộ đếm written được tăng lên theo tổng số byte được ghi vào luồng đầu ra. Số lượng này tối thiểu là hai cộng với chiều dài str và tối đa là hai lần cộng với chiều dài str.

+1

Câu hỏi đặt ra là tại sao chỉ có hai byte được sử dụng cho độ dài. Mặc dù không phải là trường hợp sử dụng phổ biến, điều này có vẻ giống như một giới hạn rất tùy ý. – MauganRa

13

Luôn sử dụng cùng một loại luồng khi đọc và ghi dữ liệu.Nếu bạn đang cho luồng trực tiếp vào một trình phân tích cú pháp sax, thì bạn không nên sử dụng một DataOutputStream.

Chỉ cần sử dụng

BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream()); 
bos.write(os.getBytes("UTF-8")); 
Các vấn đề liên quan