You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中如何通过JNI(C++)获取并访问assets/raw文件的URL?

在JNI中使用Android Assets/Raw目录文件的解决办法

核心说明

Assets和Raw目录下的文件是打包进APK的,没有真实的系统文件路径,所以不存在可以直接在C中使用的"URL"。必须通过JNI层的Java代码做中转,把文件内容或文件描述符传递给C。

可行方案

方案1:通过JNI传递AssetFileDescriptor给C++

这是最高效的方式,无需复制文件:

  1. Java层获取AssetFileDescriptor并调用Native方法:
// 在你的Activity或Context类中
public native void processAssetFile(AssetFileDescriptor fd);

public void callNativeCode() {
    try {
        AssetFileDescriptor fd = getAssets().openFd("your_asset_file.txt");
        processAssetFile(fd);
        fd.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  1. JNI层接收并转换为C++可用的文件描述符:
#include <jni.h>
#include <unistd.h>
#include <fcntl.h>

extern "C" JNIEXPORT void JNICALL
Java_com_your_package_YourActivity_processAssetFile(JNIEnv* env, jobject thiz, jobject asset_fd) {
    // 获取文件描述符
    jint fd = env->CallIntMethod(asset_fd, env->GetMethodID(env->GetObjectClass(asset_fd), "getFd", "()I"));
    // 获取文件起始偏移和长度
    jlong offset = env->CallLongMethod(asset_fd, env->GetMethodID(env->GetObjectClass(asset_fd), "getStartOffset", "()J"));
    jlong length = env->CallLongMethod(asset_fd, env->GetMethodID(env->GetObjectClass(asset_fd), "getLength", "()J"));

    // 在C++中通过文件描述符操作,注意从offset位置开始读取length字节
    lseek(fd, offset, SEEK_SET);
    char* buffer = new char[length];
    read(fd, buffer, length);
    
    // 处理读取到的buffer内容...
    
    delete[] buffer;
}

方案2:将Asset文件复制到外部存储,传递路径给C++

如果C++代码必须依赖文件路径,可以先把文件复制到APP私有外部存储:

  1. Java层完成文件复制:
public native void processFile(String filePath);

public void copyAssetToExternal() {
    String outPath = getExternalFilesDir(null) + "/copied_file.txt";
    File outFile = new File(outPath);
    if (!outFile.exists()) {
        try (InputStream in = getAssets().open("your_asset_file.txt");
             OutputStream out = new FileOutputStream(outFile)) {
            byte[] buffer = new byte[1024];
            int read;
            while ((read = in.read(buffer)) != -1) {
                out.write(buffer, 0, read);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    processFile(outPath);
}
  1. JNI层接收路径直接操作:
#include <jni.h>
#include <fstream>
#include <string>

extern "C" JNIEXPORT void JNICALL
Java_com_your_package_YourActivity_processFile(JNIEnv* env, jobject thiz, jstring file_path) {
    const char* path = env->GetStringUTFChars(file_path, nullptr);
    std::ifstream file(path);
    if (file.is_open()) {
        // 读取并处理文件内容...
        file.close();
    }
    env->ReleaseStringUTFChars(file_path, path);
}

方案3:直接传递文件字节数组到C++

如果文件体积较小,可以直接把整个文件读成字节数组传给C++:

  1. Java层读取文件并传递字节数组:
public native void processBytes(byte[] data);

public void sendAssetBytes() {
    try (InputStream in = getAssets().open("your_asset_file.txt")) {
        byte[] data = new byte[in.available()];
        in.read(data);
        processBytes(data);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  1. JNI层处理字节数组:
#include <jni.h>

extern "C" JNIEXPORT void JNICALL
Java_com_your_package_YourActivity_processBytes(JNIEnv* env, jobject thiz, jbyteArray data) {
    jbyte* bytes = env->GetByteArrayElements(data, nullptr);
    jsize length = env->GetArrayLength(data);
    
    // 处理字节数据...
    
    env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
}

内容的提问来源于stack exchange,提问作者david

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 19:35:24