求Android NDK示例:通过JNI将Java读取的文件传入C/C++
JNI传递文件数据到C/C++的实现示例(基于hello-jni扩展)
一、两种常见的文件传递方案
1. 传递文件路径,让C/C++直接读取
这种方式无需在Java层预读文件内容,直接传递路径给JNI,由C/C++侧打开文件读取,效率更高。
Java代码(扩展hello-jni的MainActivity)
public class MainActivity extends AppCompatActivity { static { System.loadLibrary("native-lib"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 将assets中的示例文件复制到本地存储,获取路径 String filePath = copyAssetToLocal("sample.pdf"); if (filePath != null) { String processResult = processFileFromPath(filePath); Log.d("JNI_FILE", "处理结果: " + processResult); } } private String copyAssetToLocal(String fileName) { try { File localFile = new File(getFilesDir(), fileName); if (!localFile.exists()) { InputStream is = getAssets().open(fileName); FileOutputStream fos = new FileOutputStream(localFile); byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1) { fos.write(buffer, 0, len); } is.close(); fos.close(); } return localFile.getAbsolutePath(); } catch (IOException e) { e.printStackTrace(); return null; } } // JNI方法声明 public native String processFileFromPath(String filePath); }
JNI代码(native-lib.cpp)
#include <jni.h> #include <string> #include <fstream> #include <sstream> extern "C" JNIEXPORT jstring JNICALL Java_com_example_hellojni_MainActivity_processFileFromPath( JNIEnv* env, jobject, jstring filePath) { // 转换Java字符串为C字符串 const char* path = env->GetStringUTFChars(filePath, nullptr); if (path == nullptr) { return env->NewStringUTF("路径转换失败"); } // 打开并读取文件 std::ifstream file(path); if (!file.is_open()) { env->ReleaseStringUTFChars(filePath, path); return env->NewStringUTF("文件打开失败"); } std::stringstream buffer; buffer << file.rdbuf(); std::string fileContent = buffer.str(); file.close(); env->ReleaseStringUTFChars(filePath, path); // 返回文件大小(实际可替换为PDF/Office解析逻辑) std::string result = "文件大小: " + std::to_string(fileContent.size()) + " 字节"; return env->NewStringUTF(result.c_str()); }
2. 传递文件字节数组到C/C++
如果已经在Java层读取了文件内容,可以直接将字节数组传给JNI处理。
Java代码新增部分
public native String processFileFromBytes(byte[] fileBytes); // 在onCreate中调用 byte[] fileBytes = readAssetToBytes("sample.docx"); if (fileBytes != null) { String result = processFileFromBytes(fileBytes); Log.d("JNI_FILE", "字节数组处理结果: " + result); } // 读取assets文件为字节数组 private byte[] readAssetToBytes(String fileName) { try { InputStream is = getAssets().open(fileName); byte[] bytes = new byte[is.available()]; is.read(bytes); is.close(); return bytes; } catch (IOException e) { e.printStackTrace(); return null; } }
JNI代码新增函数
extern "C" JNIEXPORT jstring JNICALL Java_com_example_hellojni_MainActivity_processFileFromBytes( JNIEnv* env, jobject, jbyteArray fileBytes) { jsize byteLen = env->GetArrayLength(fileBytes); jbyte* bytes = env->GetByteArrayElements(fileBytes, nullptr); if (bytes == nullptr) { return env->NewStringUTF("字节数组获取失败"); } // 直接操作字节数组(可传给PDF/Office解析库处理) std::string result = "接收字节数组长度: " + std::to_string(byteLen) + " 字节"; env->ReleaseByteArrayElements(fileBytes, bytes, 0); return env->NewStringUTF(result.c_str()); }
二、C/C++解析PDF/Office文件的扩展方向
要解析PDF或docx文件,需集成对应的C/C++库:
- PDF解析:可使用MuPDF、Poppler等轻量级库,将库编译为Android兼容的
.so文件后,在JNI代码中调用其API解析文件路径或字节数组。 - docx解析:docx本质是ZIP包,可使用minizip库解压后解析内部XML结构,或使用专门的文档解析库。
伪代码示例(基于MuPDF解析PDF)
#include <mupdf/fitz.h> std::string parsePdfPageCount(const char* path) { fz_context* ctx = fz_new_context(nullptr, nullptr, FZ_STORE_UNLIMITED); if (!ctx) return "MuPDF初始化失败"; fz_try(ctx) { fz_register_document_handlers(ctx); fz_document* doc = fz_open_document(ctx, path); int pageCount = fz_count_pages(ctx, doc); fz_close_document(ctx, doc); fz_drop_context(ctx); return "PDF页数: " + std::to_string(pageCount); } fz_catch(ctx) { fz_drop_context(ctx); return "PDF解析失败"; } } // 在processFileFromPath中替换原有逻辑为: std::string result = parsePdfPageCount(path);
内容的提问来源于stack exchange,提问作者p2511
相关产品推荐
相关产品推荐

