当前位置: 首页 > 面试题库 >

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

郎鹤龄
2023-03-14
问题内容

当我尝试在套接字上使用sax解析xml时,遇到了一种奇怪的情况。经过分析,我注意到DataOutputStream在我的数据前面添加了2个字节。

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>

使用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>

可能已经注意到,DataOutputStream在消息前面添加了两个字节。因此,sax解析器将引发异常“
org.xml.sax.SAXParseException:序言中不允许内容”。但是,当我跳过这2个字节时,sax解析器可以正常工作。另外,我注意到DataInputStream无法读取Transformer消息。

我的问题是:为什么DataOutputStream添加这些字节,为什么不使用Transformer?

对于那些有兴趣复制问题的人,这里有一些代码:

使用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();

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

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

客户端使用DataInputStream:

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

问题答案:

的输出DataOutputStream.writeUTF()是自定义格式,供读取DataInputStream.readUTF()

writeUTF您正在调用的方法的Javadocs 说:

使用修改后的UTF-8编码以独立于机器的方式将字符串写入基础输出流。

首先,将两个字节写入输出流,就像通过writeShort给出后续字节数的方法一样。该值是实际写入的字节数,而不是字符串的长度。按照长度,使用修改后的字符的UTF-8编码,依次输出字符串的每个字符。如果未引发异常,则计数器written将增加写入输出流的字节总数。长度至少str为2加3倍,长度最多为2加3倍str



 类似资料:
  • 问题内容: AJAX通话: 我收到以下错误:。但是,当我使用Postman时,我只需要添加带有url 的标头即可返回字符串。 请给我一些帮助,以解决问题。 我的目标是允许原始服务器以及正确提供的API密钥从Web Api取回数据。 问题答案: 在请求中添加标头会触发您的浏览器首先发送CORS预检OPTIONS请求。除了定义为CORS安全列出的请求标头的标头之外,添加到请求中的 任何 标头都将触发您

  • 我有一个在开头、中间和结尾有多个空白的字符串:。 我使用正则表达式(https://stackoverflow.com/a/2932439/13136767)删除了多余的空白,并将其替换为组1(它是一个空空间)。 预期产出: 实际产量: 替换字符串是在搜索和替换过程中替换每个正则表达式匹配的文本。字符串开头的大空格应该被一个空格替换。为什么没有在字符串的开头加一个空格?

  • 问题内容: 我有这两个课(表) 还有这个: 运行此代码后,在数据库(student_course)中创建了一个额外的表,现在我想知道如何在该表中添加额外的字段,例如(Grade,Date和…(我的意思是student_course表)),我看到了一些解决方案,但我不喜欢它们,而且我对它们有一些问题: 第一个样品 问题答案: 如果在链接表(STUDENT_COURSE)上添加额外的字段,则必须根据s

  • 问题内容: path = “/Volumes/Users” >>> path.lstrip(‘/Volume’) ‘s/Users’ >>> path.lstrip(‘/Volumes’) ‘Users’ >>> 我期望的输出是 问题答案: 是基于字符的,它将删除该字符串中左端的所有字符。 要验证这一点,请尝试以下操作: 由于是字符串的一部分,因此将其删除。 您需要改用切片: 或者,在Python

  • 问题内容: 我有一个带有某些样式的简单html页面,但我不明白为什么会增加一些顶部边距? 来源如下: 如果我添加“ margin-top:0;” 到了空间已经消失了……但是直到我明白为什么我才感到不高兴。 问题答案: 上的空白来自浏览器添加到元素的默认样式。例如,如果您打开的并检查元素,您将看到这样的样式。该用户代理样式表是指浏览器默认样式。保证金变成16px为浏览器有一个默认。 由于浏览器之间的

  • 我在学Windows上的汇编,想弄清楚栈上的值是什么。< br > Visual C #文档说明高于RSP的值是: 分配空间 保存了RBP 返回地址 注册主页(RCX、RDX、R8、R9) 函数参数 问题是堆栈中有32个额外的字节,文档中没有提到。 在内存快照中,RSP从0x0000000000DAF5E0开始。彩色框为: 黄色:两个值为9的64位变量 白色:保存旧RBP返回地址 蓝色:函数参数