最近工作中遇到的问题,简单记录下。

问题的情形是这样的:

由于需要用到 MapReduce 的 task side-effect files特性,在写 side-effect 文件时,用到了 FSDataOutputStream 类的 writeUTF() 方法。问题在于用 FSDataOutputStream.writeUTF() 写数据时,开头总会被多写入一个字符;而这个字符看起来是随机的,有时是乱码……

 

对于开头被多写入的字符,我一开始并没能定位到是 FSDataOutputStream.writeUTF() 的问题;后来与 System.out.println() 的输出结果对比后,才最终确定是 FSDataOutputStream.writeUTF() 多写入了一个字符。

既然问题已经被定位到,那么处理起来便很简单了。在 Stack Overflow 上看到两个帖子(1, 2),算是确定问题的源头了。

 

问题出在 Java 的 DataOutputStream.writeUTF() API 上,与 MapReduce 没有直接关系。用 FSDataOutputStream.writeUTF() 调用之所以会出问题,是因为类 FSDataOutputStream 继承了类 DataOutputStream

查看 FSDataOutputStream 的 API 文档,可以看到类 FSDataOutputStream 的原型声明如下,从中可以看到类 FSDataOutputStream 与类 DataOutputStream 的继承关系。

org.apache.hadoop.fs
@org.apache.hadoop.classification.InterfaceAudience.Public @org.apache.hadoop.classification.InterfaceStability.Stable public class FSDataOutputStream
extends java.io.DataOutputStream
implements Syncable, CanSetDropBehind

 

为什么 DataOutputStream.writeUTF() 在写数据时,会多写入两个字节呢?

DataOutputStream.writeUTF() 方法原型如下:

public final void writeUTF(String str)
				   throws IOException

JDK 里对 DataOutputStream.writeUTF() 的说明如下:

Writes a string to the underlying output stream using modified UTF-8 encoding in a machine-independent manner.

First, two bytes are written to the output stream as if by the writeShort method giving the number of bytes to follow. 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. If no exception is thrown, the counter written is incremented by the total number of bytes written to the output stream. This will be at least two plus the length of str, and at most two plus thrice the length of str.

多写入的两个字节用来表示 DataOutputStream.writeUTF() 实际写入的字节数,而不是字符串的长度。(在 Java 中,一个 char 占用两个字节)

最后,如何解决 DataOutputStream.writeUTF() 多写入字节的问题呢?换用 DataOutputStream.writeBytes() 方法即可。

 

参考链接:

One thought on “MapReduce FSDataOutputStream 写数据有误”

Leave a Reply

Your email address will not be published. Required fields are marked *