理解二进制文件

时间:2014-11-10 04:50:14

标签: java binary randomaccessfile

这是一个冗长的问题,所以坚持下去......

我试图读取一个二进制文件,该文件具有包含记录行的数据库布局。有一个两字节的整数表示新行/记录的开始。

我对该文件的了解是:

它有以下标签,其最大长度与之相关

NAME_LENGTH = 32;
LOCATION_LENGTH = 64;
SPECIALTIES_LENGTH = 64;
SIZE_LENGTH = 6;
RATE_LENGTH = 8;
OWNER_LENGTH = 8;

还有一个占用前72个字节的标题(用十六进制编辑器识别,但我们跳过这个,所以我开始在字节72处读取)。

考虑到这一点,我有限的理解是我可以读取每个值可以包含在变量中的总字节数。例如,如果名字是" John"前四个字节表示John的名称,其余部分表示空白。然后我假设我可以继续读取下一个字节获取下一个值。

我整理了一个方法来做到这一点

    private Contract retrieveContract(long locationInFile) throws IOException {

    final byte[] input = new byte[Contract.RECORD_LENGTH];

    synchronized (database) {
        database.seek(locationInFile);
        database.readFully(input);
    }

    class RecordFieldReader {
        private int offset = 0;

        String read(int length) throws UnsupportedEncodingException {
            String str = new String(input, offset, length, "UTF-8");
            offset += length;
            return str.trim();
        }
    }

    RecordFieldReader readRecord = new RecordFieldReader();

    String name = readRecord.read(Contract.NAME_LENGTH);
    String location = readRecord.read(Contract.LOCATION_LENGTH);
    String specialties = readRecord.read(Contract.SPECIALTIES_LENGTH);
    String size = readRecord.read(Contract.SIZE_LENGTH);
    String rate = readRecord.read(Contract.RATE_LENGTH);
    String owner = readRecord.read(Contract.OWNER_LENGTH);

    return "DELETED".equals(name) ? null : new Contract(name, location, specialties, size, rate, owner);
}

Contract.x的值如下所述在一个单独的类中(这里的总体目标是将每个记录读入自己的对象)

static final int NAME_LENGTH = 32;
static final int LOCATION_LENGTH = 64;
static final int SPECIALTIES_LENGTH = 64;
static final int SIZE_LENGTH = 6;
static final int RATE_LENGTH = 8;
static final int OWNER_LENGTH = 8;

static final int RECORD_LENGTH = NAME_LENGTH
        + LOCATION_LENGTH
        + SPECIALTIES_LENGTH
        + SIZE_LENGTH
        + RATE_LENGTH
        + OWNER_LENGTH;

上面提到的是前几个记录是如何对齐的,但是它们似乎遍布整个地方

此处输出为gist(有点遗憾)

最后系统崩溃了

java.io.EOFException
at java.io.RandomAccessFile.readFully(RandomAccessFile.java:421)
at java.io.RandomAccessFile.readFully(RandomAccessFile.java:399)
at suncertify.db.ContractFileAccess.retrieveContract(ContractFileAccess.java:99)
at suncertify.db.ContractFileAccess.getContractList(ContractFileAccess.java:63)
at suncertify.db.ContractFileAccess.<init>(ContractFileAccess.java:45)
at suncertify.db.Main.main(Main.java:17)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

最后问题出现了:如果我不断读取每个字段的最大值并输出它然后移动到下一个块来读取,那么为什么输出会随着文件越往下而变得混乱?< / p>

为了完整性,原始输入是另一个gist

1 个答案:

答案 0 :(得分:1)

有时将它放在公共场所会让你以不同的方式思考它。问题是我没有考虑到两个字节的分隔符。这可以通过在记录长度上加上+2来解决。

 static final int RECORD_LENGTH = 2 + NAME_LENGTH
        + LOCATION_LENGTH
        + SPECIALTIES_LENGTH
        + SIZE_LENGTH
        + RATE_LENGTH
        + OWNER_LENGTH;

感谢StackOverflow成为一个咆哮和解决的地方;)