Java - IDX文件:如何阅读它们?

时间:2017-11-27 10:50:18

标签: java image-processing

在机器学习过程中,教授要求我们使用SVM实现手写数字的分类器。他给了我们这个dataset,其中还包含一套测试分类器的列车。

我尝试编写一个java类来读取数据集并将其转换为数据结构(例如HashMap),但在阅读文件时遇到了很多困难。在数据集的网站上,有这个IDX文件的结构:

基本格式为:

magic number 
size in dimension 0 
size in dimension 1 
size in dimension 2 
..... 
size in dimension N 
data

幻数是一个整数(MSB优先)。前2个字节始终为0.

第三个字节编码数据类型:

0x08: unsigned byte 
0x09: signed byte 
0x0B: short (2 bytes) 
0x0C: int (4 bytes) 
0x0D: float (4 bytes) 
0x0E: double (8 bytes)

第4个字节编码向量/矩阵的维数:向量为1,矩阵为2 ....

每个维度的大小为4字节整数(MSB优先,高端,与大多数非英特尔处理器一样)。

数据存储在C数组中,即最后一维中的索引变化最快。

所以我开始使用文件t10k-labels-idx1-ubyte:

[offset] [type]          [value]          [description] 
0000     32 bit integer  0x00000801(2049) magic number (MSB first) 
0004     32 bit integer  10000            number of items 
0008     unsigned byte   ??               label 
0009     unsigned byte   ??               label 
........ 
xxxx     unsigned byte   ??               label

这是它的结构,所以我编写了一个java类,它应该读取文件并计算幻数和项数。这是班级:

public class ReadTest {

static String testLabel = "t10k-labels-idx1-ubyte";

public static void main(String[] args) {

    byte[] bytes = null;
    byte[] fileName = testLabel.getBytes(StandardCharsets.UTF_8);

    try {bytes = Files.readAllBytes(Paths.get(testLabel));}
    catch (IOException e) {System.err.println("Error: " + e.getMessage());}

    if(bytes != null) {

        List<Byte> listBytes = new ArrayList<>();
        List<Byte> listName = new ArrayList<>();

        for(int i=0; i<bytes.length; i++) listBytes.add(bytes[i]);
        for(int i=0; i<fileName.length; i++) listName.add(fileName[i]);

        System.out.println("I read " + listBytes.size() + " bytes!");
        System.out.println("Filename: " + listName.size() + " bytes!");

        if(listBytes.containsAll(listN)) System.out.println("Gotcha!");

        byte[] magic = {bytes[3], bytes[2], bytes[1], bytes[0]};
        byte[] items = {bytes[7], bytes[6], bytes[5], bytes[4]};

        System.out.println("[REVERSE] Magic: " + ByteBuffer.wrap(magic).getInt() + ". Items: " + ByteBuffer.wrap(items).getInt());
        System.out.println("[AFTER 32] Magic: " + ByteBuffer.wrap(bytes, 32, 4).getInt() + ". Items: " + ByteBuffer.wrap(bytes, 36, 4).getInt());
        System.out.println("[RAW] Magic: " + ByteBuffer.wrap(bytes, 0, 4).getInt() + ". Items: " + ByteBuffer.wrap(bytes, 4, 4).getInt());

        }

    }
}

我期待,作为输出,“魔术:2049.物品:10000”,但事实并非如此。在开始时我只读取前8个字节([RAW]打印),然后我尝试以相反的顺序读取它们([REVERSE]打印)。之后,我在文件上运行了一个hexdump,试图了解问题所在:如果我不理解错误,在IDX文件中有一个包含该文件信息的标题,包括名称。所以,我将文件名转换为字节数组,并使用两个List,我发现我是对的(希望如此)。所以我尝试跳过前32个字节,再次计算这两个数字,但没有成功。

我是否在实施中犯了错误?是否有一些类可以帮助我正确读取这些文件?

对于looong帖子感到抱歉,但我试图解释整个过程(:

0 个答案:

没有答案