Objective-C 到 C++ 将二进制文件读入多维浮点数组

Objective-C to C++ reading binary file into multidimensional array of float

我想将以下代码从 objective C 转换为 C++。

在 class myClass 中,我有这个属性:

float tab[dim1][dim2][dim3];

在objective-C文件中,多维数组由二进制文件填充:

NSData *dataTab=[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"pathOfMyTab" ofType:@""]];
[dataTab getBytes:myClass -> tab  length:[dataTab length]];

如何将这部分翻译成 C++?

看看fstream, fread and read,都是读取二进制文件,选择适合的方法。

在我看来,最简单和最快的方法是使用 memcpy() 将 NSData 的字节复制到与源数组具有相同结构(维度)的目标数组中。参见,例如:

https://github.com/Voldemarus/MultiDimensionalArrayDemo/tree/master

#import "DemoClass.h"

#define DIM1    3
#define DIM2    4
#define DIM3    2

@interface DemoClass() {
    int src[DIM1][DIM2][DIM3];  // source (initial) array

    int dst[DIM1][DIM2][DIM3];  // destination array
}
@end

@implementation DemoClass

- (instancetype) init
{
    if (self = [super init]) {
        for (int i = 0; i < DIM1; i++) {
            for (int j = 0; j < DIM2; j++) {
                for (int k = 0; k < DIM3; k++) {
                    int value = i*100 + j*10 + k;
                    src[i][j][k] = value;
                }
            }
        }
    }
    return self;
}

int getIntFromArray(int *array, int i, int j, int k) {
    int offset = j*DIM3 + i*DIM2*DIM3;
    return array[offset];
}

void putIntToArray(int *array, int i, int j, int k, int value) {
    int offset = j*DIM3 + i*DIM2*DIM3;
    array[offset] = value;
}

- (void) run
{
    // Step 1. Save array into NSData
    NSInteger s = sizeof(int)*DIM1*DIM2*DIM3;
    NSData *data = [[NSData alloc] initWithBytes:src length:s];
    NSAssert(data, @"NSData should be created");
    //Step2 - Create new array
    int *bytes = (int *)[data bytes];
    memcpy(dst,bytes,s);
    // Step 3. Compare src and dst
    for (int i = 0; i < DIM1; i++) {
        for (int j = 0; j < DIM2; j++) {
            for (int k = 0; k < DIM3; k++) {
                int template = i*100 + j*10 + k;
                int s = src[i][j][k];
                int d = dst[i][j][k];
 //               NSLog(@"i %d j %d k %d -->s = %d  d = %d",i,j,k,s,d);
                NSAssert(s == template, @"Source array should have value from template");
                NSAssert(d == s, @"Destination array should be identical to the source");
            }
        }
    }

}

@end

float tab[dim1][dim2][dim3]看起来像一个三维数组。标准实现是三个嵌套的 FOR 循环。

因此您的 C++ 实现可能如下所示:

  • 从某处读取dim1dim2dim3,通常是文件中的第一个值(例如12个字节,每个数字4个字节)
  • 在三个嵌套的 FOR 循环中读取文件的其余部分

类似于:

    for (size_t i = 0; i < dim1; ++i) 
       for (size_t j = 0; j < dim2; ++j)
         for (size_t k = 0; k < dim3; ++k)
           tab[i][j][k] = read_float_value(inputFile);

在Objective-C中你可以用类似的方式写文件。

以下是一些可以帮助您入门的示例:

  • Three dimensional arrays of integers in C++
  • 3D array C++ using int [] operator

我假设您的文件包含数组的字节表示形式。如果是这种情况,那么要仅使用 C++ 来模拟 Objective-C 代码的行为(唯一使此 C++ 成为 reinterpret_cast<> 的行为,否则它就是直接的 C),您可以使用以下代码。我没有添加任何错误检查,但在您可能想要执行的地方留下了一些评论。

float tab[dim1][dim2][dim3];

CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef dataTabURL = CFBundleCopyResourceURL(mainBundle, CFSTR("pathOfMyTab"), NULL, NULL);

CFReadStreamRef stream = CFReadStreamCreateWithFile(NULL, dataTabURL); // check for NULL return value
CFReadStreamOpen(stream);                                              // check for errors here
CFReadStreamRead(stream, reinterpret_cast<UInt8 *>(tab), sizeof tab);  // check that this function returns the number of bytes you were expecting (sizeof tab)
CFReadStreamClose(stream);

// we own "stream" and "dataTabURL" because we obtained these through functions
// with "create" in the name, therefore we must relinquish ownership with CFRelease
CFRelease(stream);
CFRelease(dataTabURL); // ditto

如果您在 std::string 中已经有了可用的路径,那么您可以使用以下 C++ 代码来模仿 Objective-C 代码的行为:

// make sure to include this header
#include <fstream>

// ... then elsewhere in your .cpp file ...
float tab[dim1][dim2][dim3];

std::string path = "path/to/mytab"; // obtain from somewhere
std::ifstream input(path, std::ios::binary); // check that the file was successfully opened
input.read(reinterpret_cast<char *>(tab), sizeof tab); // check that input.gcount() is the number of bytes you expected

我相信在这种情况下我们必须使用 reinterpret_cast<> 因为文件包含数组的实际表示(假设它以前以类似的方式写入文件)。

您可以使用混合方法,一旦您拥有包含资源路径的 CFURLRef,您就可以使用 this function 获得 URL 的文件系统表示(提供一个适当大小的输出缓冲区来存储结果),并且从那里你应该能够将它传递给 std::ifstream 的构造函数之一(尽管你可能需要转换为适当的类型)。

C++ 不支持可变长度数组(数组的大小必须在编译时已知)。标准库也没有提供矩阵类型,因此如果 table 的尺寸在 运行 时间发生变化,那么您将需要一种完全独立的方法来解决我的答案中的问题。您可以考虑序列化 Objective-C 的输出(使用例如 JSON 或其他格式),以便矩阵的维度也写入输出,从而更容易在 C++ 中解析文件。