通过JNI C+&#x2B读取Android Asset File失败了

发布于 2025-02-08 18:59:45 字数 1651 浏览 0 评论 0原文

我用JNI C ++代码制作了Android应用。

要在Android本机代码(C ++)上创建APK时读取模型文件,我将模型文件放在Assets文件夹中。 (因此,文件路径为my_app/src/main/assets/model.tflite

然后,我尝试读取以下代码的模型,但错误已增加:

kotlin代码>代码:

private val context: Context
    get() = getApplication<Application>().applicationContext

asset_manager = context.assets

c ++代码:

AAssetManager* mgr = AAssetManager_fromJava(env, asset_manager);
AAssetDir* assetDir = AAssetManager_openDir(mgr, "");
const char* filename = (const char*)NULL;
while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL) {
    AAsset* asset = AAssetManager_open(mgr, filename, AASSET_MODE_STREAMING);
    __android_log_print(ANDROID_LOG_INFO, "tag", "file name is: %s", filename);  <- file name reading is ok
    char buf[BUFSIZ];
    int nb_read = 0;
    FILE* out = fopen(filename, "w");                            <- out has null FILE*
    while ((nb_read = AAsset_read(asset, buf, BUFSIZ)) > 0)
        fwrite(buf, nb_read, 1, out);
    fclose(out);
    AAsset_close(asset);
}
AAssetDir_close(assetDir);

logcat

2022-06-19 22:45:54.449 12180-12180/com.my.first.app I/tag: file name is: model.tflite
2022-06-19 22:45:54.449 12180-12180/com.my.first.app A/libc: FORTIFY: fwrite: null FILE*
2022-06-19 22:45:54.450 12180-12180/com.my.first.app A/libc: Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 12180 (st.app), pid 12180 (st.app)

为什么fopen(fileName,“ w”)返回null?看来aassetManager是有效的。

I have made android app with jni C++ code.

To read model file while creating apk on android native code(C++), I placed the model file in assets folder. (so file path is my_app/src/main/assets/model.tflite)

Then, I tried to read the model with following code but an error has raised:

Kotlin code:

private val context: Context
    get() = getApplication<Application>().applicationContext

asset_manager = context.assets

C++ code:

AAssetManager* mgr = AAssetManager_fromJava(env, asset_manager);
AAssetDir* assetDir = AAssetManager_openDir(mgr, "");
const char* filename = (const char*)NULL;
while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL) {
    AAsset* asset = AAssetManager_open(mgr, filename, AASSET_MODE_STREAMING);
    __android_log_print(ANDROID_LOG_INFO, "tag", "file name is: %s", filename);  <- file name reading is ok
    char buf[BUFSIZ];
    int nb_read = 0;
    FILE* out = fopen(filename, "w");                            <- out has null FILE*
    while ((nb_read = AAsset_read(asset, buf, BUFSIZ)) > 0)
        fwrite(buf, nb_read, 1, out);
    fclose(out);
    AAsset_close(asset);
}
AAssetDir_close(assetDir);

logcat :

2022-06-19 22:45:54.449 12180-12180/com.my.first.app I/tag: file name is: model.tflite
2022-06-19 22:45:54.449 12180-12180/com.my.first.app A/libc: FORTIFY: fwrite: null FILE*
2022-06-19 22:45:54.450 12180-12180/com.my.first.app A/libc: Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 12180 (st.app), pid 12180 (st.app)

Why does fopen(filename, "w") return null? It seems that AAssetManager is work.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

盛夏尉蓝 2025-02-15 18:59:45

多亏了@botje,我可以按以下方式将model.tflite加载到资产中:

AAssetManager* mgr = AAssetManager_fromJava(env, asset_manager);
AAssetDir* assetDir = AAssetManager_openDir(mgr, "");
const char* filename = nullptr;
while ((filename = AAssetDir_getNextFileName(assetDir)) != nullptr) {
    AAsset* asset = AAssetManager_open(mgr, filename, AASSET_MODE_STREAMING);
    size_t size = AAsset_getLength(asset);
    buf = new char[size];
    memmove(buf, AAsset_getBuffer(asset), size);

    AAsset_close(asset);
  }
AAssetDir_close(assetDir);

std::unique_ptr<tflite::FlatBufferModel> model = tflite::FlatBufferModel::BuildFromBuffer((const char*)buf, size);
std::unique_ptr<tflite::Interpreter> interpreter;
tflite::ops::builtin::BuiltinOpResolver op_resolver;
tflite::InterpreterBuilder(*model, op_resolver)(&interpreter);

Thanks to @Botje, I can load the model.tflite in assets by this way:

AAssetManager* mgr = AAssetManager_fromJava(env, asset_manager);
AAssetDir* assetDir = AAssetManager_openDir(mgr, "");
const char* filename = nullptr;
while ((filename = AAssetDir_getNextFileName(assetDir)) != nullptr) {
    AAsset* asset = AAssetManager_open(mgr, filename, AASSET_MODE_STREAMING);
    size_t size = AAsset_getLength(asset);
    buf = new char[size];
    memmove(buf, AAsset_getBuffer(asset), size);

    AAsset_close(asset);
  }
AAssetDir_close(assetDir);

std::unique_ptr<tflite::FlatBufferModel> model = tflite::FlatBufferModel::BuildFromBuffer((const char*)buf, size);
std::unique_ptr<tflite::Interpreter> interpreter;
tflite::ops::builtin::BuiltinOpResolver op_resolver;
tflite::InterpreterBuilder(*model, op_resolver)(&interpreter);
一刻暧昧 2025-02-15 18:59:45

Looks like you want to combine this loading code to load the asset into a memory buffer and then use the

std::unique_ptr<tflite::Allocation> readAsset(std::string target) {
  AAssetManager* mgr = AAssetManager_fromJava(env, asset_manager);
  AAssetDir* assetDir = AAssetManager_openDir(mgr, "");
  const char* filename = nullptr;
  while ((filename = AAssetDir_getNextFileName(assetDir)) != nullptr) {
    if (target != filename)
      continue;

    AAsset* asset = AAssetManager_open(mgr, filename, AASSET_MODE_STREAMING);
    auto len = AAsset_getLength(asset);
    uint8_t *buf = new uint8_t[len];
    std::copy_n(AAsset_getBuffer(asset), len, buf);
    auto ret = std::make_unique<tflite::Allocation>(buf , len);
    AAsset_close(asset);
    AAssetDir_close(assetDir);
    return ret;
  }
  AAssetDir_close(assetDir);
  return {};
}

然后稍后将其使用为:

auto ptr = readAssset("model.tflite");
if (!ptr) {
  // do something
}

auto modelPtr = tflite::FlatBufferModel::BuildFromAllocation(ptr, some_error_reporter);
if (!modelPtr) {
  // do something
}

注意:this will> will 泄漏内存,因为tflite拥有所有权缓冲区。

Looks like you want to combine this loading code to load the asset into a memory buffer and then use the BuildFromAllocation method:

std::unique_ptr<tflite::Allocation> readAsset(std::string target) {
  AAssetManager* mgr = AAssetManager_fromJava(env, asset_manager);
  AAssetDir* assetDir = AAssetManager_openDir(mgr, "");
  const char* filename = nullptr;
  while ((filename = AAssetDir_getNextFileName(assetDir)) != nullptr) {
    if (target != filename)
      continue;

    AAsset* asset = AAssetManager_open(mgr, filename, AASSET_MODE_STREAMING);
    auto len = AAsset_getLength(asset);
    uint8_t *buf = new uint8_t[len];
    std::copy_n(AAsset_getBuffer(asset), len, buf);
    auto ret = std::make_unique<tflite::Allocation>(buf , len);
    AAsset_close(asset);
    AAssetDir_close(assetDir);
    return ret;
  }
  AAssetDir_close(assetDir);
  return {};
}

and then use it later as:

auto ptr = readAssset("model.tflite");
if (!ptr) {
  // do something
}

auto modelPtr = tflite::FlatBufferModel::BuildFromAllocation(ptr, some_error_reporter);
if (!modelPtr) {
  // do something
}

Note: this will leak memory, as TFlite takes ownership of the buffer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文