在HBase中将bytes[]转换为字符串

3

我有以下行存储在HBase表中

 DIEp(^o^)q3    column=DIE:ID, timestamp=1346194191174, value=\x00\x00\x00\x01

我试图访问该值并将其转换为字符串表示形式,应该是1,但是当我使用cat命令查看输出文件时,我没有获得正确的字符串表示形式。

cat /hadoop/logs/userlogs/job_201209121654_0027/attempt_201209121654_0027_m_000000_0/stdout

我得到了类似垃圾的东西 NUL NUL NUL SOH

以下是我正在使用的代码片段。

byte[] result1 = value.getValue("DIE".getBytes(), "ID".getBytes());
String myresult = Bytes.toString(result1);
System.out.println(myresult);

什么是字符编码?调用new String(byte[], charset)是否会给您正确的字符串? - Stephen Connolly
我猜测字符编码应该是UTF-8。 - fanbondi
猜测字符编码是失败的捷径。那些接受字节数组而不接受编码的方法版本本来就不应该被放任自流。;-) - Stephen Connolly
根据我的回答的评论,结合数据和期望的输出,我不认为“value”一开始就是一个字符串的二进制表示,此时编码的问题也就没有意义了。- @StephenConnolly - Jon Skeet
3个回答

8

标准的HBase字符串转换方式是使用Bytes.toBytes(string)和Bytes.toString(bytes)。但是Jon Skeet提醒我们需要考虑首先如何将数据放入列中。如果你使用了Bytes.toBytes(int),那么在将其转换为字符串之前,你需要先将字节转换回整数。


3
我们只是使用了new String(byte[]),其中byte[]来自org.apache.hadoop.hbase.KeyValue.getValue(),将HBase列中的字节解析为字符串,它对我们的项目有效。 :) 如果我在问题中漏掉了什么,请见谅。希望这能帮到您。

在发布这个问题之前,我真的做了一些研究,并且使用了它,但它给我提供了与问题中指定的相同的输出。我正在做类似于以下的事情。 String val = new String(myByteArray) - fanbondi
你是在尝试读取Hadoop的日志/输出文件吗?我们已经在MapReduce中成功实现了这一点。您可以具体说明想从哪里读取HBase表吗? - vikas
我也不理解哪个HBase API包含value.getValue("DIE".getBytes(), "ID".getBytes())这个方法。 - vikas
我正在从我的独立HBase集群中读取HBase表。关于API,getValue是来自org.apache.hadoop.hbase.client.Result.getValue(byte[], byte[])。 - fanbondi
1
由于@Jon的解决方案已经解决了您的问题,因此似乎您已经使用p.add(Bytes.toBytes(“DIE”),Bytes.toBytes(“ID”),Bytes.toBytes(1))插入了记录。即在存储时值为1而不是“1”,如果是这种情况,则String.valueOf(Bytes.toLong(result1))应该可以正常工作,无需进行任何位运算。另外,我认为问题尚未解决,因为它没有回答为什么HBase API无法执行其预期的操作。 :) - vikas
显示剩余2条评论

2
首先,我建议不要使用没有指定编码的String.getBytes()方法。代码实际上需要什么编码?在调用"DIE".getBytes()"ID".getBytes()时明确指定编码。
其次,看起来你应该先将这4个字节转换为一个整数,然后再将该整数转换为一个字符串。例如:
byte[] valueAsBytes = ...;
int valueAsInt = ((valueAsBytes[0] & 0xff) << 24) |
                 ((valueAsBytes[1] & 0xff) << 16) |
                 ((valueAsBytes[2] & 0xff) << 8) |
                 (valueAsBytes[3] & 0xff);
String valueAsString = String.valueof(valueAsInt);

Java API中可能有一些直接进行位操作的内容,但我现在想不起来了。(有DataInputStream,但那需要先在一个ByteArrayInputStream中包装字节数组,然后您需要检查字节序...)

您当前的代码正在按照您的要求执行-尽管使用平台的默认编码。您基本上获得了"\u0000\u0000\u0000\u0001"。


@fanbondi:你看过你得到的数据字节吗?那些不是“1”的文本编码。 - Jon Skeet
@StephenConnolly:UCS-4 不会给你 "1" - 它会给你 "\u0001",这是完全不同的。我不会为已知的 固定大小 整数值使用 BigInteger。 - Jon Skeet
我们不知道它的固定大小。因为问题没有给出这个细节,而在我的书中,更简单且经过验证的正确代码每次都获胜;-)(但每个人都有自己的选择) - Stephen Connolly
@JonSkeet 我担心低级别的文本编码对我来说可能是新的。所以我不确定如何检查它。 - fanbondi
@fanbondi:从根本上讲,看起来你的数据不是文本数据。因此不要试图将其视为文本数据。 - Jon Skeet
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接