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++?
在我看来,最简单和最快的方法是使用 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++ 实现可能如下所示:
- 从某处读取
dim1
、dim2
、dim3
,通常是文件中的第一个值(例如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++ 中解析文件。
我想将以下代码从 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++?
在我看来,最简单和最快的方法是使用 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++ 实现可能如下所示:
- 从某处读取
dim1
、dim2
、dim3
,通常是文件中的第一个值(例如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++ 中解析文件。