【问题标题】:Java : DataInputStream replacement for endiannessJava:DataInputStream 替换字节序
【发布时间】:2011-11-06 15:32:11
【问题描述】:

下面是我的代码,它替换了 DataInputStream 以包装 InputStream,但除了读取大端类型的普通方法之外,还提供了额外的方法来读取小端数据类型。如果您愿意,请随意使用它。

我有一些保留如下。注意不改变功能的方法(读取大端类型的函数)。我无法将 DataInputStream 实现为基类并使用它的方法,如 read()、readInt()、readChar() 等?

我的类层次结构在这里似乎有点奇怪。这样合适吗?

readUTF() 或 readLine() 等其他类型是否需要小端版本?或者这对特定程序来说是主观的?

Java 如何存储布尔类型?这对字节顺序也是主观的吗?

感谢您满足我的好奇心 :)

import java.io.*;

/**
 * Replacement for a DataInputStream that provides both little and big endian reading capabilities for convenience without need to implement a ByteBuffer
 * @author Bill (unspecified.specification@gmail.com)
 */
public class EndianInputStream extends InputStream implements DataInput {
    private DataInputStream dataInStream;
    private InputStream inStream;
    private byte byteBuffer[];

    /**
     * Constructor to wrap InputStream for little and big endian data
     * @param refInStream Inputstream to wrap
     */
    public EndianInputStream(InputStream refInStream) {
        inStream = refInStream;
        dataInStream = new DataInputStream(inStream);
        byteBuffer = new byte[8]; // Largest data type is 64-bits (8 bytes)
    }

    @Override
    public int available() throws IOException {
        return dataInStream.available();
    }

    @Override
    public final int read(byte refBuffer[], int offset, int readLen) throws IOException {
        return inStream.read(refBuffer, offset, readLen);
    }

    @Override
    public int read() throws IOException {
        return inStream.read();
    }

    @Override
    public final int readUnsignedByte() throws IOException {
        return dataInStream.readUnsignedByte();
    }

    @Deprecated
    @Override
    public final String readLine() throws IOException {
        return dataInStream.readLine();
    }

    @Override
    public final String readUTF() throws IOException {
        return dataInStream.readUTF();
    }

    @Override
    public final void close() throws IOException {
        dataInStream.close();
    }

    @Override
    public final void readFully(byte refBuffer[]) throws IOException {
        dataInStream.readFully(refBuffer, 0, refBuffer.length);
    }

    @Override
    public final void readFully(byte refBuffer[], int offset, int readLen) throws IOException {
        dataInStream.readFully(refBuffer, offset, readLen);
    }

    @Override
    public final int skipBytes(int n) throws IOException {
        return dataInStream.skipBytes(n);
    }

    @Override
    public final boolean readBoolean() throws IOException {
        return dataInStream.readBoolean();
    }

    @Override
    public final byte readByte() throws IOException {
        return dataInStream.readByte();
    }

    @Override
    public final float readFloat() throws IOException {
        return Float.intBitsToFloat(readInt());
    }

    @Override
    public final double readDouble() throws IOException {
        return Double.longBitsToDouble(readLong());
    }

    @Override
    public final short readShort() throws IOException {
        return dataInStream.readShort();
    }

    @Override
    public final int readUnsignedShort() throws IOException {
        return dataInStream.readUnsignedShort();
    }

    @Override
    public final long readLong() throws IOException {
        return dataInStream.readLong();
    }

    @Override
    public final char readChar() throws IOException {
        return dataInStream.readChar();
    }

    @Override
    public final int readInt() throws IOException {
        return dataInStream.readInt();
    }

    /**
     * Reads floating point type stored in little endian (see readFloat() for big endian)
     * @return float value translated from little endian
     * @throws IOException if an IO error occurs
     */
    public final float readLittleFloat() throws IOException {
        return Float.intBitsToFloat(readLittleInt());
    }    

    /**
     * Reads double precision floating point type stored in little endian (see readDouble() for big endian)
     * @return double precision float value translated from little endian
     * @throws IOException if an IO error occurs
     */    
    public final double readLittleDouble() throws IOException {
        return Double.longBitsToDouble(readLittleLong());
    }

    /**
     * Reads short type stored in little endian (see readShort() for big endian)
     * @return short value translated from little endian
     * @throws IOException if an IO error occurs
     */    
    public final short readLittleShort() throws IOException {
    dataInStream.readFully(byteBuffer, 0, 2);
    return (short)((byteBuffer[1] & 0xff) << 8 | (byteBuffer[0] & 0xff));
    }

    /**
     * Reads char (16-bits) type stored in little endian (see readChar() for big endian)
     * @return char value translated from little endian
     * @throws IOException if an IO error occurs
     */    
    public final char readLittleChar() throws IOException {
        dataInStream.readFully(byteBuffer, 0, 2);
        return (char)((byteBuffer[1] & 0xff) << 8 | (byteBuffer[0] & 0xff));
    }    

    /**
     * Reads integer type stored in little endian (see readInt() for big endian)
     * @return integer value translated from little endian
     * @throws IOException if an IO error occurs
     */        
    public final int readLittleInt() throws IOException {
        dataInStream.readFully(byteBuffer, 0, 4);
        return (byteBuffer[3]) << 24 | (byteBuffer[2] & 0xff) << 16 |
            (byteBuffer[1] & 0xff) << 8 | (byteBuffer[0] & 0xff);
    }

    /**
     * Reads long type stored in little endian (see readLong() for big endian)
     * @return long value translated from little endian
     * @throws IOException if an IO error occurs
     */        
    public final long readLittleLong() throws IOException {
        dataInStream.readFully(byteBuffer, 0, 8);
        return (long)(byteBuffer[7]) << 56 | (long)(byteBuffer[6]&0xff) << 48 |
            (long)(byteBuffer[5] & 0xff) << 40 | (long)(byteBuffer[4] & 0xff) << 32 |
            (long)(byteBuffer[3] & 0xff) << 24 | (long)(byteBuffer[2] & 0xff) << 16 |
            (long)(byteBuffer[1] & 0xff) <<  8 | (long)(byteBuffer[0] & 0xff);
    }

    /**
     * Reads unsigned short type stored in little endian (see readUnsignedShort() for big endian)
     * @return integer value representing unsigned short value translated from little endian
     * @throws IOException if an IO error occurs
     */        
    public final int readLittleUnsignedShort() throws IOException {
        dataInStream.readFully(byteBuffer, 0, 2);
        return ((byteBuffer[1] & 0xff) << 8 | (byteBuffer[0] & 0xff));
    }
}

【问题讨论】:

    标签: java endianness


    【解决方案1】:

    readBoolean() 读取单个字节。 readLine() 读取单个字节并将每个字节转换为 char

    readUTF() 读取修改后的 UTF-8(其代码单元大小为一个八位字节)。 UTF-8 有no endianness

    这些方法没有字节序问题。

    关于设计,请考虑类型是否需要为InputStream 以及ByteBuffer 是否有用。如果您没有使用标记/重置和Closeable 等功能,您可能不会公开新类型:

    public class Bytes {
      public static DataInput littleEndian(final DataInput decorated) {
        class LittleInput implements DataInput {
          private ByteBuffer buffer = ByteBuffer.allocate(8);
    
          public int readInt() throws IOException {
            buffer.clear();
            buffer.order(ByteOrder.BIG_ENDIAN)
                .putInt(decorated.readInt())
                .flip();
            return buffer.order(ByteOrder.LITTLE_ENDIAN)
                .getInt();
          }
    
          //TODO: other methods    
        }
    
        return new LittleInput();
      }
    
    }
    

    我注意到流行的 Guava 库已经有 LittleEndianDataInputStream

    【讨论】:

    • 谢谢。 Guava 是否可以作为大多数人计算机上已有的标准 Java 运行时平台的一部分提供?
    • @user1030796 - 不,Guava 是 Google 提供的第三方库。
    • ESRI shapefile 格式在一种格式中混合了小端和大端,所以我想像这里一样从一个类中提供这两种类型。
    • 大多数时候,当我提到字节序时,人们会认为我在尝试编写跨平台代码;但是设计 ESRI shapefile 格式的人一定会笑得很开心,因为他们让它不必要地包含两个字节序
    猜你喜欢
    • 2016-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-08
    • 1970-01-01
    • 1970-01-01
    • 2019-03-15
    • 1970-01-01
    相关资源
    最近更新 更多