简体   繁体   English

为什么 DataOutputStream.writeUTF() 在开头添加额外的 2 个字节?

[英]Why does DataOutputStream.writeUTF() add additional 2 bytes at the beginning?

When I was trying to parse xml using sax over sockets I came across a strange occurence.当我试图通过套接字使用 sax 解析 xml 时,我遇到了一个奇怪的现象。 Upon analysing I noticed that DataOutputStream adds 2 bytes in front of my data.在分析时,我注意到 DataOutputStream 在我的数据前面添加了 2 个字节。

Message send by DataOutputStream: 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>

Message send using Transformer:使用 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>  

As one might notice DataOutputStream adds two bytes in front of the message.人们可能会注意到 DataOutputStream 在消息前面添加了两个字节。 Thus the sax parser throws the exception "org.xml.sax.SAXParseException: Content is not allowed in prolog.".因此,sax 解析器会抛出异常“org.xml.sax.SAXParseException: Content is not allowed in prolog.”。 However when I skip over these 2 bytes the sax parser works just fine.但是,当我跳过这 2 个字节时,sax 解析器工作得很好。 Additional I noticed that DataInputStream is unable to read the Transformer message.另外我注意到 DataInputStream 无法读取 Transformer 消息。

My question is: Why does DataOutputStream adds these bytes and why doesn't the Transformer?我的问题是:为什么 DataOutputStream 添加这些字节而 Transformer 为什么不添加?




For those who are interested in replicating the problem here is some code:对于那些有兴趣复制问题的人,这里有一些代码:

Server using DataInputStream:使用 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 using Transformer:使用 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;
}


Client using SAX Parser:使用 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);

Client using DataInputStream:使用 DataInputStream 的客户端:

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

The output of DataOutputStream.writeUTF() is a custom format, intended to be read by DataInputStream.readUTF() . DataOutputStream.writeUTF()的输出是一种自定义格式,旨在由DataInputStream.readUTF()读取。

The javadocs of the writeUTF method you are calling say:您正在调用的writeUTF方法的 javadocs 说:

Writes a string to the underlying output stream using modified UTF-8 encoding in a machine-independent manner.以独立于机器的方式使用修改后的 UTF-8 编码将字符串写入底层输出流。

First, two bytes are written to the output stream as if by the writeShort method giving the number of bytes to follow.首先,两个字节被写入输出流,就像通过writeShort方法给出要跟随的字节数一样。 This value is the number of bytes actually written out, not the length of the string.该值是实际写出的字节数,而不是字符串的长度。 Following the length, each character of the string is output, in sequence, using the modified UTF-8 encoding for the character.在长度之后,使用修改后的 UTF-8 字符编码按顺序输出字符串的每个字符。 If no exception is thrown, the counter written is incremented by the total number of bytes written to the output stream.如果没有抛出异常, written的计数器会增加写入输出流的总字节数。 This will be at least two plus the length of str , and at most two plus thrice the length of str .这将至少是str长度的两倍,最多是str长度的两倍加三倍。

Always use the same type of stream when reading and writing data.读取和写入数据时始终使用相同类型的流。 If you are feeding the stream directly into a sax parser, then you should not use a DataOutputStream.如果您将流直接提供给 sax 解析器,则不应使用 DataOutputStream。

Just use只需使用

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 android socket DataOutputStream.writeUTF - android socket DataOutputStream.writeUTF 从DataOutputStream.writeUTF()读取时如何获取Java字符串的“原始”字节? - How to get 'original' bytes of a Java String when read from DataOutputStream.writeUTF()? 通过DataOutputStream.writeUTF()发送信息时出现奇怪的字符 - strange characters when sending information via DataOutputStream.writeUTF() 在线程中循环 DataOutputStream writeUTF - Looping DataOutputStream writeUTF in thread java.io.DataOutputStream 中的 writeUTF - writeUTF in java.io.DataOutputStream 为什么DataOutputStream的writeByte()和ObjectOutputStream的writeByte()写的字节不同? - Why Bytes written by writeByte() of DataOutputStream and writeByte() of ObjectOutputStream are different? 从DataOutputStream重新分配给BufferedOutputStream和FileOutputStream之后,再也无法使用writeUTF() - Not able to use writeUTF() anymore after reassigning to BufferedOutputStream and FileOutputStream from DataOutputStream DataOutputStream是否不生成字节作为输出? - DataOutputStream not generating bytes as output? Java将单个字节写入DataOutputStream - Java write individual bytes to DataOutputStream 文件开头的附加“ 2000”字符串([32 30 30 30]字节) - Additional “2000” String ([32 30 30 30] bytes) at the beginning of a file
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM