2011-10-03 13 views
9

Cuando estaba tratando de analizar XML utilizando sax sockets, me encontré con una extraña ocurrencia. Al analizar, noté que DataOutputStream agrega 2 bytes a mis datos.¿Por qué DataOutputStream.writeUTF() agrega 2 bytes adicionales al principio?

Mensaje enviar por 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> 

Enviar mensaje usando Transformador:

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> 

Como es de notar DataOutputStream añade dos bytes en frente del mensaje. Por lo tanto, el analizador de sax arroja la excepción "org.xml.sax.SAXParseException: el contenido no está permitido en prolog". Sin embargo, cuando omito estos 2 bytes, el analizador de sax funciona bien. Adicional Noté que DataInputStream no puede leer el mensaje Transformador.

Mi pregunta es: ¿Por qué DataOutputStream agrega estos bytes y por qué no el transformador?




Para aquellos que estén interesados ​​en replicar el problema aquí es un poco de código:

Server mediante 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 mediante transformador:

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; 
} 


cliente utilizando analizador SAX:

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); 

cliente utilizando 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

No sé si se hace una diferencia, pero su primer texto XML no tiene el 'encoding = 'UTF-8''. –

+0

Además, ¿por qué querrías usar DataInputStream? Eso no es necesario cuando lee XML. – StaxMan

+0

DataInputStream se utilizó para las pruebas ya que no sabía que utiliza su propio protocolo. –

Respuesta

21

La salida de DataOutputStream.writeUTF() es un formato personalizado, destinado a ser leído por DataInputStream.readUTF().

Los javadocs del método writeUTF que están pidiendo por ejemplo:

Graba una serie en la secuencia de salida subyacente modificada usando codificación UTF-8 de una manera independiente de la máquina.

En primer lugar, se escriben dos bytes en la secuencia de salida como si el método writeShort proporcionara el número de bytes a seguir. Este valor es la cantidad de bytes realmente escritos, no la longitud de la cadena. Después de la duración, cada carácter de la cadena se emite, en secuencia, utilizando la codificación UTF-8 modificada para el carácter. Si no se lanza ninguna excepción, el contador written se incrementa en la cantidad total de bytes escritos en la secuencia de salida. Esta será al menos dos más la longitud de str, y como máximo dos más tres veces la longitud de str.

+1

La pregunta es por qué solo se usan dos bytes para la longitud. Aunque no es un caso de uso común, parece un límite muy arbitrario. – MauganRa

13

Utilice siempre el mismo tipo de flujo al leer y escribir datos.Si está alimentando la transmisión directamente a un analizador de sax, entonces no debería usar un DataOutputStream.

Sólo tiene que utilizar

BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream()); 
bos.write(os.getBytes("UTF-8")); 
Cuestiones relacionadas