c++ 如何访问unique_ptr字节数组中的字节范围?

bsxbgnwa  于 2023-03-14  发布在  其他
关注(0)|答案(2)|浏览(96)
  • 更新 * 使用替代方法阅读 * 见下文 *
  • 原员额 *

我对C++还是个新手,我已经用Unreal写了一段时间的代码,但是我正在写一个文件解析器,并且把它作为一个独立的解决方案来做。我想从unique_ptr数组中的一个未知的起点读取一个未知长度的字节。我也希望对代码的清洁度或效率发表评论,希望养成良好的习惯。
我已经能够使用basic_ifstream读入文件,如下所示

auto ReadFileData(std::string path) {
    auto fileSize = std::filesystem::file_size(path);
    auto buf = std::make_unique<std::byte[]>(fileSize);
    std::basic_ifstream<std::byte> ifs(path, std::ios::binary);
    ifs.read(buf.get(), fileSize);
    return buf;
}

这将unique_ptr字节数组返回到fileData,我写了一个方法来读取一定数量的字节,以从二进制转换为get值,但它一次只接收一个字节,我觉得这会很慢。

uint32_t ParseUint32(auto& fileData, uint32_t dataLocation) {
    return uint32_t((unsigned char)(fileData[dataLocation+3]) << 24 |
        (unsigned char)(fileData[dataLocation + 2]) << 16 |
        (unsigned char)(fileData[dataLocation + 1]) << 8 |
        (unsigned char)(fileData[dataLocation]));
}

但是我已经到了需要读入压缩范围的字节来解压缩其中的数据的地步,我似乎没有得到任何关于memcpy的东西,并且读到unique_ptr数组不能被复制,最后一行是我卡住的地方。

for(uint16_t i = 0; i<tileOffsetCount; i++)
{
    tileOffsets[i] = ParseUint32(fileData,tileOffset + (i*4));
    uint32_t tileByteSize = ParseUint32(fileData,tileByteCountsOffset +(i*4)) ;
    char* tileData = new char[tileByteSize];
    std::memcpy(tileData, fileData+tileOffsets[i],tileByteSize); //This line is where I'm stuck
}
w1jd8yoj

w1jd8yoj1#

unique_ptr s确实不能被复制(unique_ptr s的复制向量和复制赋值操作符被删除),但是仍然可以复制unique_ptr所指向的部分数据。
我怀疑问题出在这个加法fileData+tileOffsets[i]上,这里fileDataunique_ptrtileOffsets[i]uint32_t,但是我不认为存在这样的加法运算符,你可以试着把表达式修改成fileData.get()+tileOffsets[i],这里加上get()也不是坏事,因为我们只是用得到的指针复制一些数据,而不存储该指针(存储指针是为了以后,这通常会导致麻烦)。
我不认为以下部分是常见的,甚至可能做得更有效

uint32_t ParseUint32(auto& fileData, uint32_t dataLocation) {
    return uint32_t((unsigned char)(fileData[dataLocation+3]) << 24 |
        (unsigned char)(fileData[dataLocation + 2]) << 16 |
        (unsigned char)(fileData[dataLocation + 1]) << 8 |
        (unsigned char)(fileData[dataLocation]));
}

我所知道的唯一值得注意的是,如果你想让程序真正跨平台,那么在存储和加载多字节数据到文件系统,或者通过网络发送数据时,最好注意字节序。

z3yyvxxp

z3yyvxxp2#

  • 最新消息 *

我使初始文件阅读变得过于复杂,这使它变得更加困难。使用查找和读取是我在C#中做过的事情,应该在这里实现。而且,它要快得多...

std::ifstream ReadFileData(std::string path) {
    std::ifstream dataFile(path,std::ios::binary);
    return dataFile;
}

uint32_t ParseUint32(std::ifstream& fileData, uint32_t dataLocation) {
    char memblock[4]{};  
    fileData.seekg(dataLocation);
    fileData.read(memblock,4);
    return uint32_t(((unsigned char)memblock[3]) << 24 |
        ((unsigned char)memblock[2]) << 16 |
        ((unsigned char)memblock[1]) << 8 |
        ((unsigned char)memblock[0]));
}

char* ParseDataBlock(std::ifstream& fileData, uint32_t dataLocation, uint32_t dataSize) {
    char* memblock = new char[dataSize]; 
    fileData.seekg(dataLocation);
    fileData.read(memblock,dataSize);
    return memblock;
}

int main() {
    std::string filePath = "my/filepath/";
    for (const auto& entry : std::filesystem::directory_iterator(filePath)) {
        std::string filePath = { entry.path().string()};
        if (filePath.substr(filePath.size() - 3) == "tif") {
            std::ifstream fileData = ReadFileData(filePath);
            uint32_t* tileOffsets = new uint32_t[tileOffsetCount];
            for(uint16_t i = 0; i<tileOffsetCount; i++)
            {
                tileOffsets[i] = ParseUint32(fileData,tileOffset + (i*4));
                uint32_t tileByteSize = ParseUint32(fileData,tileByteCountsOffset +(i*4)) ;
                char* tileData = ParseDataBlock(fileData,tileOffsets[i],tileByteSize);
            }/....

相关问题