Java -读取结构化二进制文件

jobtbby3  于 2022-12-28  发布在  Java
关注(0)|答案(4)|浏览(168)

我刚接触Java,需要读取一个二进制文件,并显示转换为整数的内容。

{client#, position 1, size 32 | 
category, position 33, size 10 | 
type, position 43, size 10 | 
creditlimit, position 53, size 20}

我只需要一个关于使用什么类的指南和一个转换的例子,一个小片段将不胜感激。

2jcobegt

2jcobegt1#

我假设位置1实际上是0第一个字节。2文件格式似乎是固定大小记录,可能字节中有ASCII。3为了检查数据,我从字符串中的字段开始。4将它们转换为long/int可能会丢失实际内容的信息。
下面使用了一个顺序二进制文件。内存Map文件会更快,但这是可以接受的,也很短。
保存客户端数据:

class Client {
    String clientno;
    String category; 
    String type;
    String position;
    String creditlimit;

    @Override
    public String toString() {
        return String.format("Client# %s, categ %s, type %s, pos %s, creditlimit %s%n",
            clientno, category, type, position, creditlimit);
    }
}

阅读文件:

// Field sizes:
final int CLIENT_NO = 32;
final int CATEGORY = 10;
final int TYPE = 10;
final int CREDIT_LIMIT = 20;
final int RECORD_SIZE = CLIENT_NO + CATEGORY + TYPE + CREDIT_LIMIT;

byte[] record = new byte[RECORD_SIZE];
try (BufferedInputStream in = new BufferedInputStream(
    new FileInputStream(file))) {

    for (;;) {
         int nread = in.read(record);
         if (nread < RECORD_SIZE) {
             break;
         }
         Client client = new Client();
         int offset = 0;
         int offset2 = offset + CLIENT_NO;
         client.clientno = recordField(record, offset, offset2 - offset);
         offset = offset2;
         int offset2 = offset + CATEGORY;
         client.category = recordField(record, offset, offset2 - offset);
         offset = offset2;
         int offset2 = offset + TYPE;
         client.type = recordField(record, offset, offset2 - offset);
         offset = offset2;
         int offset2 = offset + CREDITLIMIT;
         client.creditlimit = recordField(record, offset, offset2 - offset);

         System.out.println(client);
    }

} // Closes in.

使用字段提取:

private static String recordField(byte[] record, int offset, int length) {
    String field = new String(record, offset, length, StandardCharsets.ISO_8859_1);

    // Use ASCII NUL as string terminator:
    int pos = field.indexOf('\u0000');
    if (pos != -1) {
        field = field.substring(0, pos);
    }

    return field.trim(); // Trim also spaces for fixed fields.
}
r1wp621o

r1wp621o2#

如果我没理解错你的问题,你应该使用NIO Package
使用byteBuffer类中的asIntBuffer(),可以得到ByteBufferIntBuffer视图,并且通过调用get(int[] dst),可以将其转换为整数。
初始的ByteBuffer可以通过使用file channels获得。

q3qa4bjr

q3qa4bjr3#

如果您使用二进制数据,可能JBBP会是您的舒适方式,使用框架解析和打印数据结构非常容易(如果我正确理解了任务,并且您使用字节字段),示例解析整个输入流,然后将解析后的数据打印到控制台

@Bin class Record {byte [] client; byte [] category;  byte [] type; byte [] creditlimit;};
@Bin class Records {Record [] records;};
Records parsed = JBBPParser.prepare("records [_] {byte [32] client; byte [10] category; byte [10] type; byte [20] creditlimit;}").parse(THE_INPUT_STREAM).mapTo(Records.class);
System.out.println(new JBBPTextWriter().Bin(parsed).toString());
7xllpg7q

7xllpg7q4#

根据您的描述,二进制数据包含4个字段,并且有明确的偏移量,但不清楚数据类型是什么,大小是什么意思,字节长度还是位长度,还是其他什么?
为了澄清这个问题,我们需要做以下假设:

  1. 4个字段为字符串类型;
  2. size表示字节长度;
    1.使用UTF-8编码
    推荐你一个java工具(FastProto)来快速解析二进制文件。
import org.indunet.fastproto.annotation.*;

public class File {
    @StringType(offset = 1, length = 32)
    String client;
 
    @StringType(offset = 33, length = 10)
    String category;

    @StringType(offset = 43, length = 10)
    String type;

    @StringType(offset = 53, length = 20)
    String creditLimit;
}

byte[] bytes = ... // the binary file
File file = FastProto.parse(bytes, File.class);

也许你已经注意到,FastProto通过注解来描述二进制数据中的字段信息,非常简单高效,如果是其他数据类型,FastProto也支持。

相关问题