2

我正在做一个项目,我应该将其写入ByteArray文件。然后,使用 C++ 程序读取同一个文件。

ByteArray写入文件的内容是这三个的组合ByteArrays-

  • 2 个字节是我的schemaId,我用短数据类型表示它。
  • 然后下一个8 字节是我的Last Modified Date,我用长数据类型表示它。
  • 剩余字节可以是可变大小,这是我的属性的实际值..

将结果ByteArray写入文件后。现在我需要从该文件中读取C++ program并读取将包含 ByteArray 的第一行,然后按照我上面提到的那样相应地拆分生成的 ByteArray 以便我能够从中提取我schemaIdLast Modified Date和我的实际attribute value

我一直用 Java 完成所有的编码,而且我是 C++ 的新手......我能够用 C++ 编写一个程序来读取文件,但不知道我应该如何以这样的方式读取 ByteArray,以便我能够像我上面提到的那样拆分它..

下面是我的 java 代码,它将生成的 ByteArray 写入一个文件,现在我需要从 c++ 中读回同一个文件。

public static void main(String[] args) throws Exception {

    String os = "whatever os is";
    byte[] avroBinaryValue = os.getBytes();

    long lastModifiedDate = 1379811105109L;
    short schemaId = 32767;

    ByteArrayOutputStream byteOsTest = new ByteArrayOutputStream();
    DataOutputStream outTest = new DataOutputStream(byteOsTest);
    outTest.writeShort(schemaId);
    outTest.writeLong(lastModifiedDate);
    outTest.writeInt(avroBinaryValue.length);
    outTest.write(avroBinaryValue);

    byte[] allWrittenBytesTest = byteOsTest.toByteArray();

    DataInputStream inTest = new DataInputStream(new ByteArrayInputStream(allWrittenBytesTest));

    short schemaIdTest = inTest.readShort();

    long lastModifiedDateTest = inTest.readLong();

    int sizeAvroTest = inTest.readInt();
    byte[] avroBinaryValue1 = new byte[sizeAvroTest];
    inTest.read(avroBinaryValue1, 0, sizeAvroTest);


    System.out.println(schemaIdTest);
    System.out.println(lastModifiedDateTest);
    System.out.println(new String(avroBinaryValue1));

    writeFile(allWrittenBytesTest);
}

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

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

        FileOutputStream output = new FileOutputStream(file);
        IOUtils.write(byteArray, output);           
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

下面是我的 C++ 程序,它正在读取上述文件(由 Java 编写),我不确定我应该怎么做才能以这种方式拆分 ByteArrays,以便我可以相应地读取单个 ByteArrays..

#include "ReadFile.h"
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main () {
    string line;

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

    //check to see if the file is opened:
    if (myfile.is_open())
    {
        //while there are still lines in the
        //file, keep reading:
        while (! myfile.eof() )
        {

        // I am not sure what I am supposed to do here?

        }

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

    else cout << "Unable to open file";

    return 0;
}

在反序列化单个 ByteArray 之后,我应该能够从上述 C++ 程序中提取 schemaId as 32767lastModifiedDateas1379811105109和我的 Attribute 值。whatever os is

我是 C++ 新手,因此面临很多问题。基于我的代码的任何示例都将帮助我更好地理解。

任何人都可以帮助我吗?谢谢。

更新:-

下面是我能够提取的最新代码schemaIdlastModifiedDateattributeLength

但不确定如何提取实际的属性值-

int main() {
    string line;

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

    if (myfile.is_open()) {

        uint16_t schemaId;
        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
        schemaId = *reinterpret_cast<uint16_t*>(buffer);

        cout<< schemaId <<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;

      // not sure how to extract the actual attribute value?

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

    else
        cout << "Unable to open file";

    return 0;
}
4

1 回答 1

3

在 Java 中,您的程序是

  1. 写入架构 ID
  2. 写最后修改日期
  3. 写avro二进制数据长度
  4. 写入avro二进制数据

所以在 C++ 中你的程序是

  1. 读取架构 ID
  2. 读取最后修改日期
  3. 读取avro二进制数据长度
  4. 读取avro二进制数据

对于这个程序,C++ 和 Java 之间的区别真的很小,所以如果你能用 Java 做,你应该(稍加研究)就能用 C++ 做。

这是一个开始(第 1 项)

short schemaId;
myFile.read(reinterpret_cast<char*>(&schemaId), sizeof(short));

reinterpret_cast<char*>是必要的,因为 read 函数char*的第一个参数需要一个。因此,如果第一个参数不是指向 char 的指针,则需要强制转换。

这确实假设sizeof(short) == 2(在 Java 中总是如此,在 C++ 中通常如此),并且不存在字节顺序问题。很难知道这一点,您只需要尝试一下即可。

在读取或写入二进制整数时,您的 Java 和 C++ 实现可能会使用不同的字节顺序。这称为字节序。如果是这种情况,那么您在读取整数时将不得不交换字节顺序。这里有一些代码可以做到这一点(这是非常乏味的东西,可能有更简洁的方法)。

uint16_t schemaId;
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
schemaId = *reinterpret_cast<uint16_t*>(buffer);

// 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);

ETC...

您需要#include <algorithm>获取该std::swap功能。

于 2013-09-30T20:00:58.227 回答