8

我有巨大的大型机文件,并且该文件中有一些压缩数字。我想知道如何使用java解压后面的数字?

压缩数字:?

我阅读了解包数字的教程,发现以下规则来计算解包数字所需的字节数:

total_number_of_bytes = (no. of digits + 1) / 2

我编写了以下代码来解压缩数字:

public String unpackData(String packedData, int decimalPointLocation) {
        String unpackedData = "";
        char[] characters = packedData.toCharArray();
        final int impliedPositive = 15;
        final int positiveNumber = 12;
        final int negativeNumber = 13;
        for (int currentCharIndex = 0; currentCharIndex < characters.length; currentCharIndex++) {
            byte[] unpackedDigits = unpackByte((byte) characters[currentCharIndex]);
            if(currentCharIndex == (characters.length - 1)) {
                if(unpackedDigits[1] == impliedPositive || unpackedDigits[1] == positiveNumber) {
                    unpackedData += String.valueOf(unpackedDigits[0]);
                } else if(unpackedDigits[1] == negativeNumber) {
                    unpackedData = "-" + unpackedData;
                }
            } else {
                unpackedData += String.valueOf(unpackedDigits[0]) + String.valueOf(unpackedDigits[1]);
            }
        }
        if(decimalPointLocation > 0) {
            unpackedData = unpackedData.substring(0, (decimalPointLocation - 1)) + 
                            "." + 
                            unpackedData.substring(decimalPointLocation);
        }
        return unpackedData;
    }

    private byte[] unpackByte(byte packedData) {
        byte firstDigit = (byte) (packedData >>> 4);
        firstDigit = setBitsToZero(firstDigit, 4, 8);

        //System.out.println(" firstDigit = "+ firstDigit + ", and its bit string after unpacking = " + getBitString(firstDigit, 7));

        byte secondDigit = setBitsToZero(packedData, 4, 8);
        //System.out.println("second digit = " + secondDigit + ", and its bit string of second digit after unpcking = " + getBitString(secondDigit, 7));

        byte[] unpackedData = new byte[2];
        unpackedData[0] = firstDigit;
        unpackedData[1] = secondDigit;
        return unpackedData;
    }

    private byte setBitsToZero(byte number, int startBitPosition, int endBitPosition) {
        for (int i = startBitPosition; i < endBitPosition; i++) {
            number =  (byte) (number & ~(1 << i));
        }
        return number;
    }

该程序适用于整数类型值,但不适用于浮点类型值。

谁能告诉我的程序是否正确?

4

4 回答 4

9

COMP-3(或“压缩十进制”)数据如下所示:0x12345s,其中“s”是 C 表示正数,D 表示负数,或 F 表示无符号数。因此 0x12345c -> “12345”、x012345d -> “-12345”和 0x12345f -> “12345”。

您有一个明显的错误:如果符号为负,您将忽略包含符号 nybble 的字节中的 nybble(例如,上面的“5”)。此外,您在操纵 nybble 方面工作得太辛苦了,这是一个简单的按位与或 4 位移位来隔离 nybble。

尝试这样的事情(未经测试):

public String unpackData(String packedData, int decimalPointLocation) {
    String unpackedData = "";
    char[] characters = packedData.toCharArray();
    final int negativeSign = 13;
    for (int currentCharIndex = 0; currentCharIndex < characters.length; currentCharIndex++) {
        byte firstDigit = ((byte) characters[currentCharIndex]) >>> 4);
        byte secondDigit = ((byte) characters[currentCharIndex]) & 0x0F;
        unpackedData += String.valueOf(firstDigit);
        if (currentCharIndex == (characters.length - 1)) {
            if (secondDigit == negativeSign) {
                unpackedData = "-" + unpackedData;
            }
        } else {
            unpackedData += String.valueOf(secondDigit);
        }
    }
    if (decimalPointLocation > 0) {
        unpackedData = unpackedData.substring(0, (decimalPointLocation - 1)) + 
                        "." + 
                        unpackedData.substring(decimalPointLocation);
    }
    return unpackedData;
}
于 2013-12-03T22:46:48.863 回答
4
public static final int UNSIGNED_BYTE = 0xff;
public static final int BITS_RIGHT = 0xf;

public long parseComp3(byte[] data) {
    long val = 0L;
    boolean negative = false;
    for (int i = 0; i < data.length; i++) {
        int raw = data[i] & UNSIGNED_BYTE;
        int digitA = raw >> 4;
        int digitB = raw & BITS_RIGHT;

        if (digitA < 10) {
            val *= 10L;
            val += (long) digitA;

        } else if (digitA == 11 || digitA == 13) { // Some non-IBM systems store the sign on left or use 11 for negative.
            negative = true;
        }

        if (digitB < 10) {
            val *= 10L;
            val += (long) digitB;

        } else if (digitB == 11 || digitB == 13) {
            negative = true;
        }
    }
    if (negative)
        val = -val;
    return val;
}
于 2014-05-02T14:59:00.230 回答
4

Ross Paterson 解决方案在将前 4 位向右移动时存在错误。必须应用掩码 0x0F。

以下是更正的方法:

private static String unpackData(byte[] packedData, int decimalPointLocation) {
    String unpackedData = "";

    final int negativeSign = 13;
    for (int currentCharIndex = 0; currentCharIndex < packedData.length; currentCharIndex++) {
        byte firstDigit = (byte) ((packedData[currentCharIndex] >>> 4) & 0x0F);
        byte secondDigit = (byte) (packedData[currentCharIndex] & 0x0F);
        unpackedData += String.valueOf(firstDigit);
        if (currentCharIndex == (packedData.length - 1)) {
            if (secondDigit == negativeSign) {
                unpackedData = "-" + unpackedData;
            }
        } else {
            unpackedData += String.valueOf(secondDigit);
        }
    }

    if (decimalPointLocation > 0) {
        int position = unpackedData.length() - decimalPointLocation;
        unpackedData = unpackedData.substring(0, position) + "." + unpackedData.substring(position);
    }
    return unpackedData;
}
于 2017-06-09T11:42:57.267 回答
1

我已经测试了Ross Paterson解决方案,但运行不正常,但有一些小细节。谢谢罗斯,也谢谢鲍勃博士的“int raw”

测试解决方案在这里:

private static String unpackData(byte[] packedData, int decimals) {
    String unpackedData="";
    final int negativeSign = 13;
    int lengthPack = packedData.length;
    int numDigits = lengthPack*2-1;

    int raw = (packedData[lengthPack-1] & 0xFF);
    int firstDigit = (raw >> 4);
    int secondDigit = (packedData[lengthPack-1] & 0x0F);
    boolean negative = (secondDigit==negativeSign);
    int lastDigit = firstDigit;
    for (int i = 0; i < lengthPack-1; i++) {
        raw = (packedData[i] & 0xFF);
        firstDigit = (raw >> 4);
        secondDigit = (packedData[i] & 0x0F);
        unpackedData+=String.valueOf(firstDigit);
        unpackedData+=String.valueOf(secondDigit);

    }
    unpackedData+=String.valueOf(lastDigit);
    if (decimals > 0) {
        unpackedData = unpackedData.substring(0,numDigits-decimals)+"."+unpackedData.substring(numDigits-decimals);
    }
    if (negative){
        return '-'+unpackedData;
    }
    return unpackedData;
}

以及将解包数据转换为打包数据的函数:

private static byte[] packData(String unpackedData) {
    int unpackedDataLength = unpackedData.length();
    final int negativeSign = 13;
    final int positiveSign = 12;
    if (unpackedData.charAt(0)=='-'){
        unpackedDataLength--;
    }

    if (unpackedData.contains(".")){
        unpackedDataLength--;
    }
    int packedLength = unpackedDataLength/2+1;

    byte[] packed = new byte[packedLength];
    int countPacked = 0;
    boolean firstHex = (packedLength*2-1 == unpackedDataLength);
    for (int i=0;i<unpackedData.length();i++){
        if (unpackedData.charAt(i)!='-' && unpackedData.charAt(i)!='.'){
            byte digit = Byte.valueOf(unpackedData.substring(i,i+1)); 
            if (firstHex){
                packed[countPacked]=(byte) (digit<<4);
            }else{
                packed[countPacked]=(byte) (packed[countPacked] | digit );
                countPacked++;
            }
            firstHex=!firstHex;
        }
    }
    if (unpackedData.charAt(0)=='-'){
        packed[countPacked]=(byte) (packed[countPacked] | negativeSign );
    }else{
        packed[countPacked]=(byte) (packed[countPacked] | positiveSign );
    }
    return packed;
}
于 2017-05-03T14:41:45.263 回答