解析包含id和数据点对的数据流的最佳方法

时间:2016-06-04 13:08:17

标签: java parsing stream byte pipes-filters

我正在尝试编写一个简单的管道和过滤器系统,我目前正在一次一个字节地解析输入流。

我的数据流遵循以下格式:

ID(4字节)DATA(8字节)ID(4字节)DATA(8字节)

每个数据框都有6对id和数据。

解析此类流的最佳做法是什么?我希望能够过滤掉id和一些数据,这样我就可以得到一个只有DATA01,DATA02等的表。

如何在第一个id(000,例如整数)之后提取第一个数据点(long),然后在第二个id(001,整​​数)之后提取第二个数据点(double)。

我希望我能够详细阐述我的问题。

提前感谢您的问候,

菲利普

4 个答案:

答案 0 :(得分:2)

试试preon。有关简单示例,请参阅此link

如果您不想使用库,那么DataInputStream可以很好地适应您的用例。有关示例,请参阅此link

答案 1 :(得分:1)

很难说出你真正希望实现的目标。

我的答案假设您需要以下内容:

public Map<Integer, Double> read(InputStream stream);

尝试这样的事情:

public static void main(String[] args) throws IOException {
    InputStream stream = ...;
    byte[] buffer = new byte[12];
    Map<Integer, Double> values = new HashMap<>();
    while (stream.read(buffer) == 12) { // Could it read all data?
        int id = readInt(buffer, 0);
        double value = readDouble(buffer, 4);
        values.put(id, value);
    }
// use values
}

public static double readDouble(byte[] data, int offset) {
    return Double.longBitsToDouble(readLong(data, offset));
}

public static long readLong(byte[] data, int offset) {
    // Do some bit shifting to adjust the numbers.
    return (((long) readInt(data, offset)) << 32) + readInt(data, offset + 4);
}

public static int readInt(byte[] data, int offset) {
    return (data[offset + 0] << 24) + (data[offset + 1] << 16) + (data[offset + 2] << 8) + (data[offset + 3]);
}

答案 2 :(得分:1)

ByteBuffer是完成你想要做的事情的好课程。 ByteBuffer允许您直接将字节数组转换为相应的原始值。这与读取缓冲区而不是一次读取一个字节相结合,您将获得相对简洁有效的解决方案!

示例:

    public void parseStream( InputStream is ) throws IOException 
    {
        boolean vtoggle = true; // Are we converting to long or double?
        ByteBuffer idBuffer = ByteBuffer.allocate( 4 ); // Initialize our id buffer
        ByteBuffer valueBuffer = ByteBuffer.allocate( 8 ); // Initialize our value buffer

        while( true /*or some real condition*/ )
        {
            idBuffer.put( readFromInput( is, 4 ) ); // Store the id bytes
            valueBuffer.put( readFromInput( is, 8 ) ); // Store the value bytes
            int id = idBuffer.getInt(); // Convert id bytes
            if( vtoggle )
            {
                long lvalue = valueBuffer.getLong(); // Convert long bytes
                // Do something with value
            }
            else
            {
                double dvalue = valueBuffer.getDouble(); // Convert double bytes
                // Do something with value
            }
            idBuffer.clear(); // Reset id buffer
            valueBuffer.clear(); // Reset value buffer
            vtoggle = !vtoggle; // Code to alternate whether or not we are converting to long or double
        }
    }

    /**
     * Read and return a certain number of bytes from our stream
     */
    public byte[] readFromInput( InputStream is, int count ) throws IOException
    {
        byte[] buffer = new byte[ count ];
        int bytesRead = 0;
        int offset = 0;
        while( ( bytesRead = is.read( buffer, offset, buffer.length - offset  ) ) > 0 )
        {
            offset += bytesRead;
        }
        if( offset == buffer.length )
        {
            return buffer;
        }
        else
        {
            throw new IOException( "Unexpected end to stream." );
        }
    }

这显然只是一个模板,但希望它能指导您找到解决问题的正确方法。

答案 3 :(得分:0)

请提供一些示例代码!

我猜你有一些ByteArrayInputStream?请查看API:https://docs.oracle.com/javase/7/docs/api/java/io/ByteArrayInputStream.html

您可以简单地将read(...)方法用于您的目的:https://docs.oracle.com/javase/7/docs/api/java/io/ByteArrayInputStream.html#read(byte[],%20int,%20int)

这样你可以这样做:

ByteArrayInputStream in;

byte[] id = new byte[4];
in.read(id, 0, 4);

byte[] data = new byte[8];
in.read(data, 0, 8);

只需将其放入循环中即可完成。

如果read(...)方法返回-1,则流已完成。如果read(...)方法的返回值低于您预期的返回值,也可以检查错误。