从 iOS 应用程序将文件加载到 C++ 对象/iOS <iostream> 出现问题

Loading a file into a C++ object from an iOS App / issues with <iostream> on iOS

我正在努力将 C++ 库(GRT,具体来说是一个机器学习工具包)集成到 iOS 应用程序中。

我已经将 GRT 构建为一个框架,包括使用一些 Objective-C++ 包装器函数在我的应用程序和框架之间进行调用。

目前,我正在尝试解决涉及文件加载的问题。具体来说,我正在尝试将我的应用程序包中的文件加载到 GRT 模块中。

这是我获取我想要访问的文件并初始化 GRT 包装器的地方:

func loadTrainingData(){

    let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    let fileUrl = documentsUrl.appendingPathComponent("train.grt")

    let pipeline = GestureRecognitionPipeline()
    let test:Bool = pipeline.load(fileUrl.path)
    print(test)
}

下面是调用 pipeline.load 时调用的 Obj-C++ 包装器代码:

- (BOOL)load:(NSString *) path
{
    BOOL result = self.instance->load(std::string(path.UTF8String));

    if (result) {
        std::cout << "GRT config";
        std::cout << self.instance->getModelAsString();
        std::cout << "GRT info: " << self.instance->getInfo();
    }

    return result;
}

最后,这是 GRT 库中处理文件加载的实际 C++ 代码:

bool GestureRecognitionPipeline::load(const std::string &filename){

    std::fstream file;        

    //Clear any previous setup
    clear();

    file.open(filename.c_str(), std::iostream::in );

    if( !file.is_open() ){
        errorLog << __GRT_LOG__ << " Failed to open file with filename: " << filename << std::endl;
        return false;
    }
    ...
 }

目前,我总是无法让我的管道对象成功导入文件。我认为这不一定与我在 iOS 端访问文件的方式有关(尽管我可能是错的)。有没有人有任何见识?任何赞赏 - 谢谢!

编辑:我能够通过此检查验证我正在加载我的文件是否正确加载:

let path = Bundle.main.path(forResource: "acc-orientation", ofType: "grt") print(path as Any!)

但是,我仍然遇到与以前相同的问题。

EDIT 2 我验证了路径也在 Obj-C++ 包装器中正确加载;这让我认为这可能与 iOS 中的处理方式有关......现在完全迷失在这里......

编辑 3 正如同事所建议的,我尝试使用文件 url 的 absoluteString 传递给我的包装器和底层 C++ 代码,因为 C++ 无法访问 iOS 的沙盒环境。还是一样的结果:

let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]

let fileUrl = documentsUrl.appendingPathComponent("acc-orientation.grt")

let pipeline = GestureRecognitionPipeline()
let test:Bool = pipeline.load(fileUrl.absoluteString)

EDIT 4 正如评论中所建议的,我尝试使用 fileSystemRepresentation,但这也没有带来成功。

- (BOOL)load:(NSURL *) url {

    BOOL result = self.instance->load(std::string([url fileSystemRepresentation]));
   ...
}

编辑 5: 我做了一个简单的测试项目,试图只访问文件并使用 Swift->Obj-C++->C++ 加载它(没有框架文件,换句话说)。这是 link where it can be downloaded。任何帮助表示赞赏!

好吧,你快到了。我已经下载了您的示例项目并开始运行。您的问题与您要打开的文件的实际位置有关。目前您正在尝试从 Documents 文件夹中打开文件,但实际上您从未将文件从 App Bundle 复制到 Documents 文件夹。所以有两种解决方案:

解决方案 1:App Bundle

更改 ViewController.swift 中的 loadTrainingData 方法以从 App Bundle 访问文件:

func loadTrainingData(){
    let path = Bundle.main.url(forResource: "acc-orientation", withExtension: "grt")
    let wrapper = Wrapper()
    let test:Bool = wrapper.load(path)
    print(test)
}

解决方案 2:文档文件夹

在第一次启动后立即将文件从您的 App Bundle 复制到您的 Documents 文件夹。因此,将以下代码片段复制到您的 AppDelegate.swift:

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    do {
        let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("acc-orientation.grt")
        let bundleURL = Bundle.main.url(forResource: "acc-orientation", withExtension: "grt")
        try FileManager.default.copyItem(at: bundleURL!, to: url)
    } catch {
        print("File already exists")
    }
    return true
}

使用这些解决方案中的任何一个,您的 FileLoader::load 方法将 return true

希望对您有所帮助。