Android中如何通过JNI(C++)获取并访问assets/raw文件的URL?
在JNI中使用Android Assets/Raw目录文件的解决办法
核心说明
Assets和Raw目录下的文件是打包进APK的,没有真实的系统文件路径,所以不存在可以直接在C中使用的"URL"。必须通过JNI层的Java代码做中转,把文件内容或文件描述符传递给C。
可行方案
方案1:通过JNI传递AssetFileDescriptor给C++
这是最高效的方式,无需复制文件:
- 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(); } }
- 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私有外部存储:
- 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); }
- 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++:
- 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(); } }
- 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
相关产品推荐
相关产品推荐

