解析包含未知长度字段的字节数组

时间:2011-02-24 15:13:35

标签: java string parsing

我在Java中解析一个具有以下规范的字节数组:

Trace data format:
    - 4 bytes containing the Id.
    - 4 bytes containing the address.
    - N bytes containing the first name, where 0 < N < 32
    - N bytes containing the last name, where 0 < N < 32
    - 4 bytes containing the Minimum
    - 4 bytes containing the Maximum 
    - 4 bytes containing the Resource Default Level

今天我没有看到解析这个数组的任何解决方案,以获得具有正确类型的7变量。你确认或者我错过了Java中的魔术函数,允许在字节数组中找到字符串“限制”(我无法看到最小值如何与其关联的ASCII字符区分开来)。

是否有关于2个字符串之间的特殊字符的“约定”?

5 个答案:

答案 0 :(得分:12)

嗯,你知道第一个名字从字节9开始,而姓氏以字节结尾(lenght-13)。不确定的是如何找到名字的结尾和姓氏的开头。我看到了一些可能的消息:

  • 如果格式是由C程序员定义的,那么两个名称字段很可能以空字节结束,因为这是字符串的C约定。
  • 如果它是由Java程序员定义的,它可以由writeUTF()编写,这意味着字节计数的规范很可能是错误的。但是,这至少指定了编码,否则这是一个悬而未决的问题。
  • 如果它是由COBOL程序员定义的,则这两个字段可以是固定长度的,并用零或空格填充,格式规范列出有效负载长度而不是字段长度。
  • 如果它是由一个真正无能的程序员(无论什么语言)定义的,它包含两个没有分隔符或计数的名称,所以不可能实际分开它们(如果你没有信息,就没有“魔法”在Java或其他地方可以凭空创造它的功能)。我想你可能希望姓氏总是以大写字母开头,没有人使用双重名字或全部大写字母。

答案 1 :(得分:5)

  

是否有关于2个字符串之间的特殊字符的“约定”?

c-strings通常以空值终止\0

如果没有这样的字符,我会说不可能解析结构。

答案 2 :(得分:3)

假设名字和姓氏以空值终止,你可以这样做:

int firstNameLength = 0;
while(firstNameLength<32) {
    if(theArray[firstNameLength]=='0') break;
    firstNameLength++;
}
int lastNameLength = 0;
while(lastNameLength<32) {
    if(theArray[8+firstNameLength+1+lastNameLength]=='0') break;
    i++;
}
String firstName = new String(theArray).substring(8,8+firstNameLength);
String lastName = new String(theArray).substring(8+firstNameLength+1,8+firstNameLength+1+lastNameLength);

答案 3 :(得分:2)

如果要读取N个ASCII字节并将其转换为字符串。

public static String readString(DataInputStream dis, int num) throws IOException {
    byte[] bytes = new byte[num];
    dis.readFully(bytes);
    return new String(bytes, 0);
}

对于其余值,您可以使用

dis.readInt();

如果您问是否有任何方法可以知道字符串有多长,我不相信您可以从提供的信息中确定这一点。字符串可能是'0'字节终止或长度为第一个字节。也许如果你查看文件中的字节,你会看到格式是什么。

od -xc my-format.bin

答案 4 :(得分:0)

为迈克尔的回答添加另一种可能性。

假设两个字段N相同,并且由于使用了相同的字母,我猜这是这种情况,字段位置将是这样的:

int len = array.length;
int varLen = len - 5*4;
int fieldPos[] = new int[7];
fieldPos[0] = 0;
fieldPos[1] = 4;
fieldPos[2] = 8;
fieldPos[3] = 8 + varLen;
fieldPos[4] = 8 + 2*varLen;
fieldPos[5] = 8 + 2*varLen + 4;
fieldPos[6] = 8 + 2*varLen + 8;