使用java.io.DataInputStream读取二进制文件会导致错误的值

时间:2015-07-03 10:40:05

标签: java c

我在阅读包含二进制格式股票价格的文件时遇到困难。我一直在尝试浏览这里的答案,并使用谷歌搜索任何使用DataInputStream的教程,但仍然没有运气。他们都没有工作。

我还读过Java中的大小端转换,但它仍然给我错误的值。有没有人有使用Java阅读* .mkt文件的经验?我得到的代码工作正常,但它是用C编写的,但要求是用Java重写它。

该方法的目的是从

指定的每个二进制数据块中获取几个字段

if (j == 1 || j == 4 || j == 9 || j == 11 || j == 12 || j == 13 || j == 14)

下面是二进制数据和我为测试编写的代码的规范。

  

标题

     
    

转码 - >短2字节
    时间戳 - >长4字节
    消息 - >短2字节

  
     

数据

     
    

安全令牌 - >短2字节
    最后交易价格 - >长4字节
    百思买数量 - >长4字节
    百思买价格 - >长4字节
    畅销数量 - >长4字节
    最畅销价格 - >长4字节
    总交易数量 - >长4字节
    平均交易价格 - >长4字节
    开盘价 - >长4字节
    高价 - >长4字节
    低价 - >长4字节
    ClosePrice - >长4字节
    填充物 - >长4字节(空白)

  
     

总共50个字节

public static void main(String[] args) throws Exception {
    FileInputStream inputStream = new FileInputStream(new File("<Path to the file>.mkt"));
    List<String> results = readPriceFromStream(inputStream);
    inputStream.close();
    System.out.println(results.get(0));
}

public static List<String> readPriceFromStream(InputStream sourceInputStream) throws Exception {
    List<String> result = new ArrayList<>();

    DataInputStream inputStream = new DataInputStream(sourceInputStream);

    int[] byteSequences = new int[]{2, 4, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4};
    int len = 50;

    for (int i = 1; i <= inputStream.available(); i += len) {
        StringBuilder sb = new StringBuilder();
        int read = 0;

        for (int j = 0; j < byteSequences.length; j++) {
            byte[] buffer = new byte[byteSequences[j]];

            if (j == 1 || j == 4 || j == 9 || j == 11 || j == 12 || j == 13 || j == 14) {
                try {
                    sb.append(Integer.valueOf(inputStream.readLong())).append(",");
                } catch (Exception e) {
                    e.printStackTrace();
                    sb.append("0").append(",");
                }
            } else {
                read = inputStream.read(buffer, 0, byteSequences[j]);
            }
        }

        if (read <= -1) {
            break;
        } else {
            String price = sb.toString();

            if (price.length() > 0) {
                price = price.substring(0, price.lastIndexOf(","));
                result.add(price);
            }
        }
    }

    if (result.size() > 0) {
        result.remove(0);
    }

    inputStream.close();
    return result;
}

**以下是用C **编写的代码片段

for(i = 0; i <= fileLen; i=i+58) {
    fread(&TransCode, sizeof(signed short int), 1, input_filename);
    fread(&TimeStamp, sizeof(signed long int), 1, input_filename);

... Truncated for clarity ...

示例数据 Transcode,Timestamp,MessageLength,SecurityToken,LastTradedPrice,BestBuyQuantity,BestBuyPrice,BestSellQuantity,BestSellPrice,TotalTradedQuantity,AverageTradedPrice,OpenPrice,HighPrice,LowPrice,ClosePrice,Blank

  

5,1435905898,58,7,34600,1,34585,29,34600,47479,34777,34560,35100,34500,34670,0

来自main(String[] args)

的结果
  

-2416744146710362880,-615304298158882816,-7614115823107390437,149649579050240,22110525258626,139753974434839,144387995842138645

如果这是重复另一个问题或之前已经回答,请帮助指出我的问题/答案因为我现在绝望(已经花了半天试图使它工作)我对这种知识知之甚少二进制的东西。感谢。

3 个答案:

答案 0 :(得分:1)

丢失所有for (int i = 1; i <= inputStream.available(); i += len) {内容。你做错了什么。

DataInputStream inputStream = new DataInputStream(sourceInputStream);之后创建一个类似于此的循环...

try {
    while(true) {  // An EOFException is thrown when there's no more data
       short transcode = inputStream.readShort();
       int timestamp = inputStream.readInt();
       short message = inputStream.readShort();
       // and so on
    }
} catch(EOFException e) {
    // File processed
}

不要忘记Java的签名与至少某些数据字段的无符号性。

编辑:由于您的数据实际上是Little Endian格式,因此最好使用ByteBuffer类似的hinneLinks建议:

Path path = Paths.get("path/to/file");
byte[] byteArray= Files.readAllBytes(path);
ByteBuffer bbuffer = ByteBuffer.wrap(byteArray);
bbuffer.order(ByteOrder.LITTLE_ENDIAN); // Set the byte order
short numS = bbuffer.getShort();
System.out.println("short: " + numS);

答案 1 :(得分:1)

尝试

Path path = Paths.get("path/to/file");
byte[] byteArray= Files.readAllBytes(path);
ByteBuffer bbuffer = ByteBuffer.wrap(byteArray);
short numS = bbuffer.getShort();
System.out.println("short: " + numS);

如果Endian错误(例如1280而不是5),请尝试Short.reverseBytes(numS);获取单个值,或bbuffer.order(ByteOrder.LITTLE_ENDIAN);获取所有元素。

java.nio.ByteBuffer也支持阅读特定职位,例如java.nio.ByteBuffer.getShort(int)当然还有不同的数据类型。 只需使用ByteBuffer逐行(或50字节块)读取文件。

答案 2 :(得分:0)

查看byteSequences中您使用readLong读取32位数字(4字节)值的值,但java中的长度实际上是64位值(8字节),所以你最终会读到两个值。