当前位置: 首页 > 知识库问答 >
问题:

如何使用Big-Endian格式而不是Little-Endian格式?

印辉
2023-03-14

我正在使用具有Big-Endian字节顺序格式的Java将字节数组值写入文件中。。现在我需要从C程序中读取该文件。。。

我正在写入文件的字节数组由三个字节数组组成,如下所述-

short employeeId = 32767;
long lastModifiedDate = "1379811105109L";
byte[] attributeValue = os.toByteArray();

我正在将employeeIdlastModifiedDateattributeValue一起写入一个单字节数组,并将生成的字节数组写入一个文件,然后我将使用我的C程序从文件中检索该字节数组数据,然后反序列化以提取employeeIdlastModifiedDate和它的attributeValue

下面是我的工作Java代码,它将字节数组值写入大端格式的文件:

public class ByteBufferTest {

    public static void main(String[] args) {

        String text = "Byte Array Test For Big Endian";
        byte[] attributeValue = text.getBytes();

        long lastModifiedDate = 1289811105109L;
        short employeeId = 32767;

        int size = 2 + 8 + 4 + attributeValue.length; // short is 2 bytes, long 8 and int 4

        ByteBuffer bbuf = ByteBuffer.allocate(size); 
        bbuf.order(ByteOrder.BIG_ENDIAN);

        bbuf.putShort(employeeId);
        bbuf.putLong(lastModifiedDate);
        bbuf.putInt(attributeValue.length);
        bbuf.put(attributeValue);

        bbuf.rewind();

        // best approach is copy the internal buffer
        byte[] bytesToStore = new byte[size];
        bbuf.get(bytesToStore);

        writeFile(bytesToStore);

    }

    /**
     * Write the file in Java
     * @param byteArray
     */
    public static void writeFile(byte[] byteArray) {

        try{
            File file = new File("bytebuffertest");

            FileOutputStream output = new FileOutputStream(file);
            IOUtils.write(byteArray, output);           

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

现在,我需要使用下面的C程序从同一个文件中检索字节数组,并将其反序列化以从中提取employeeIdlastModifiedDateattributeValue。我不确定在C端什么是最好的方式。以下是我目前掌握的代码:

int main() {

    string line;

    std::ifstream myfile("bytebuffertest", std::ios::binary);

    if (myfile.is_open()) {

        uint16_t employeeId;
        uint64_t lastModifiedDate;
        uint32_t attributeLength;

        char buffer[8]; // sized for the biggest read we want to do

        // read two bytes (will be in the wrong order)
        myfile.read(buffer, 2);

        // swap the bytes
        std::swap(buffer[0], buffer[1]);

        // only now convert bytes to an integer
        employeeId = *reinterpret_cast<uint16_t*>(buffer);

        cout<< employeeId <<endl;

        // read eight bytes (will be in the wrong order)
        myfile.read(buffer, 8);

        // swap the bytes
        std::swap(buffer[0], buffer[7]);
        std::swap(buffer[1], buffer[6]);
        std::swap(buffer[2], buffer[5]);
        std::swap(buffer[3], buffer[4]);

        // only now convert bytes to an integer
        lastModifiedDate = *reinterpret_cast<uint64_t*>(buffer);

        cout<< lastModifiedDate <<endl;

        // read 4 bytes (will be in the wrong order)
        myfile.read(buffer, 4);

        // swap the bytes
        std::swap(buffer[0], buffer[3]);
        std::swap(buffer[1], buffer[2]);

        // only now convert bytes to an integer
        attributeLength = *reinterpret_cast<uint32_t*>(buffer);

        cout<< attributeLength <<endl;

        myfile.read(buffer, attributeLength);


        // now I am not sure how should I get the actual attribute value here?

        //close the stream:
        myfile.close();
    }

    else
        cout << "Unable to open file";

    return 0;
}

我已经专门将存储Java端设置为big-endian,这意味着我知道每个字节所属的位置。那么,如何在将字节移动到每个值的正确位置的同时对其进行编码呢?现在我把它编码成小endian我猜这不是我想要的。。。

我在某个地方读到,我可以用C中的ntoh来反序列化字节数组。。不确定与我目前拥有的相比,htons是否是更好的解决方案?。。

如果是,那么我不确定如何在我当前的C代码中使用它?

有谁能看看C代码,看看我能做些什么来改进它,因为我认为它看起来效率不高?有没有更好的方法来反序列化字节数组并在C端提取相关信息?

共有1个答案

东深
2023-03-14

如果Java和C代码是由您开发的,那么最好使用Google协议缓冲区(https://developers.google.com/protocol-buffers/docs/overview)而是编写自己的序列化程序/反序列化html" target="_blank">程序。

如果您真的想编写自己的实现,最好的方法是编写一个缓冲区类,它接收字节流作为参数(例如,作为构造函数参数),并使一些访问方法readShort/readLong/readInt/readByte。。。并且只交换所需的字节。

class ByteBuffer{
  explicit ByteBuffer(uint8_t* byteStream, uint16_t streamLength);
  uint8_t readUInt8(uint16_t readPos)const {return m_byteStream[readPos];} // no conversion needed
  uint16_t readUInt16(uint16_t readPos)const {
    const uint8_t byteCount = 2;
    union{
      uint16_t u16;
      uint8_t u8[byteCount];
    }tmp;
    for(uint8_t i=0; i<byteCount; ++i){
      tmp.u8[i] = readUInt8(readPos+i*8);
    }
    return ntohs(tmp.u16); // do conversion
  }
  ...
}

此处缺少检查缓冲区后面的读取。如果您的代码应该是可移植的,那么您必须使用ntohl/ntohs(请参阅:http://forums.codeguru.com/showthread.php?298741-C-General-What-do-ntohl()-和-htonl()-实际执行)。如果您自己交换字节,那么您的代码是不可移植的(仅在Little Endian机器上运行)。如果您使用ntoh,那么它也会在这样的机器上运行。

为了方便起见,我还编写了一个包装类,您可以在其中直接读写字段(例如雇员ID):

class MyBuffer{
  uint16_t readEmployeeId()const{return m_Buffer.readuint16(EmployeeId_Pos);}
  ....
  static const uint16_t EmployeeId_Pos = 0;
  ....
}
 类似资料:
  • 问题内容: 所有, 我一直在网上练习编码问题。目前,我正在研究问题陈述“ 问题”,我们需要在其中转换大尾数<->小尾数。但是考虑到给出的示例,我无法记下步骤: 我正在考虑的逻辑是: 1>获取整数值(由于我在Windows x86上,输入为Little Endian) 2>生成相同的十六进制表示形式。 3>反转表示并生成大端整数 但是我显然在这里缺少一些东西。 谁能指导我。我正在用Java 1.5编

  • 我目前有一个Java ByteBuffer,它已经有了Big-Endian格式的数据。然后我想写一个二进制文件作为Little Endian。 下面是刚刚用Big-Endian编写文件的代码: 请注意,byteBuff是一个以Big-Endian格式填充的ByteBuffer。 我最后的办法是使用蛮力方法创建另一个缓冲区,并将ByteBuffer设置为little endian,然后从原始(big

  • 问题内容: 我知道我们可以 但是,这种小字节序格式很难与原始Guid进行比较 如何在SQL语句中使用原始的Guid而不是little endian? 问题答案: 如果您想轻松地与原始内容进行比较而不进行转换,则将其存储为文本。它会占用更多的存储空间,并且读/写/比较会更慢,但更容易被人阅读。

  • 问题内容: 我能够将其转换为无符号整数: 这利用了Go包https://golang.org/src/encoding/binary/binary.go中的BigEndian和LittleEndian类型。 这提供了,但是没有等效项或 有什么想法为什么不呢?另外,应该怎么做呢? 问题答案: 将数字类型转换为一系列字节(),反之亦然,这与字节序有关。您如何解释结果完全取决于您。 您所需要做的就是汇编

  • 问题内容: 我正在尝试编写.txt文件,它必须是UCS-2 Little Endian,但是当我尝试 根据我的阅读,它应该是相同的,但在服务器上的特定应用程序中将无法使用。当我在Notepad ++中打开可以正常工作(手动创建)的文件时,它说它是“ UCS-2 Little Endian”,但是用Java这样创建时,它说“ UCS-2 LE w / o BO”,服务器无法读取它。 我该怎么写才能使

  • Endian Firewall Community是一个功能齐全的Linux安全发行版本,它可以将每一种系统变成一个功能齐全的安全设备,并拥有UTM的功能。其特性包括:状态数据 包检测防火墙、多种协议(HTTP、FTP、POP3、SMTP)的应用程序级代理、支持反病毒和垃圾邮件过滤、Web通信过滤和VPN。