C++解析word docx探索(二)——使用POI库进行解析

之前使用Libreoffice解析Word出现各种问题,这次使用本使用POI库进行解析和操作word,在网上查了查POI是java的jar包提供个的,解析需要使用C++调用jar包,就需要使用java的JNI技术了,详细原理不解释,自己看下,这里是说明如何用C++调用jar包:

  1. java jak下载,不说了,自己在官网上下.
  2. 开始配置环境,添加环境变量,在jdk目录下\jre\bin\client,我的是在C:\Program Files (x86)\Java\jdk1.8.0_211\jre\bin\client。
  3. 配置VS的环境,新建控制台程序,设置包含目录,jdk目录下的\jdk1.8.0_211\include和jdk1.8.0_211\include\win32目录.
  4. 设置库目录C:\Program Files %28x86%29\Java\jdk1.8.0_211\jre\bin\client和C:\Program Files %28x86%29\Java\jdk1.8.0_211\lib两个目录。
  5. 设置依赖项,jvm.lib.
    在这里插入图片描述
// CallJava.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "jni.h"
#include <windows.h>
#include <Shlwapi.h>
#include <string>

using namespace std;

typedef jint(WINAPI *_CreateJavaVM)(JavaVM **, void **, void *);
#pragma comment(lib,"Shlwapi.lib") 

/*C字符串转JNI字符串*/
jstring stoJstring(JNIEnv* env, const char* pat) {
    jclass strClass = env->FindClass( "Ljava/lang/String;");
    jmethodID ctorID = env->GetMethodID( strClass, "<init>",
        "([BLjava/lang/String;)V");
    jbyteArray bytes = env->NewByteArray(strlen(pat));
    env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);
    jstring encoding = env->NewStringUTF("utf-8");
    return (jstring)env->NewObject( strClass, ctorID, bytes,
        encoding);
}
/*JNI字符串转C字符串*/
char* jstringTostring(JNIEnv* env, jstring jstr) {
    char* rtn = NULL;
    jclass clsstring =env->FindClass("java/lang/String");
    jstring strencode =env->NewStringUTF( "utf-8");
    jmethodID mid =env->GetMethodID( clsstring, "getBytes",
        "(Ljava/lang/String;)[B");
    jbyteArray barr = (jbyteArray)env->CallObjectMethod(jstr, mid,
        strencode);
    jsize alen =env->GetArrayLength( barr);
    jbyte* ba =env->GetByteArrayElements(barr, JNI_FALSE);
    if (alen > 0) {
        rtn = (char*)malloc(alen + 1);
        memcpy(rtn, ba, alen);
        rtn[alen] = 0;
    }
   env->ReleaseByteArrayElements( barr, ba, 0);
    return rtn;
}

//创建docx文件压缩包
jobject  createOPCPackage(JNIEnv* env, const char* strpath)
{
    jclass OPCPackageClass = env->FindClass("org/apache/poi/openxml4j/opc/OPCPackage");
    if (OPCPackageClass == NULL) {
        fprintf(stderr, "createOPCPackage::FindClass failed\n");
        return NULL;
    }
    else {
        fprintf(stderr, "createOPCPackage::FindClass success\n");

    }
    jmethodID createId = env->GetStaticMethodID(OPCPackageClass, "create",
        "(Ljava/lang/String;)Lorg/apache/poi/openxml4j/opc/OPCPackage;");
    if (createId == 0) {
        fprintf(stderr, "createOPCPackage::GetMethodID failed\n");
        return NULL;
    }
    jstring strPath = stoJstring(env, strpath);

    //jobject strencode = env->NewObject(OPCPackageClass, createId, strPath);
    //if (!strencode)
    //    return NULL;
    jobject objOPCPac =  (jobject)env->CallStaticObjectMethod(OPCPackageClass, createId, strPath);
    if (objOPCPac == NULL)
    {
        fprintf(stderr, "objOPCPac::CallStaticObjectMethod failed\n");
        return NULL;
    }else{
        fprintf(stderr, "objOPCPac::CallStaticObjectMethod success\n");

    }
    return objOPCPac;

}

int _tmain(int argc, _TCHAR* argv[])
{
    int res;
    long status;
    JavaVMInitArgs vm_args;
    JavaVMOption options[3];
    JavaVM *jvm = NULL;
    JNIEnv *env = NULL;
    
    RtlZeroMemory(&vm_args, sizeof(JavaVMInitArgs));
    /*设置初始化参数*/
    options[0].optionString = "-Djava.compiler=NONE"; //Disabled JIT  
    options[1].optionString = "-Djava.class.path=.;F:/poi-4.1.0/poi-4.1.0.jar;F:/poi-4.1.0/poi-ooxml-4.1.0.jar;F:/poi-4.1.0/poi-scratchpad-4.1.0.jar;F:/poi-4.1.0/poi-ooxml-schemas-4.1.0.jar;\
                                                    F:/poi-4.1.0/lib/activation-1.1.1.jar;F:/poi-4.1.0/lib/commons-codec-1.12.jar;F:/poi-4.1.0/lib/commons-collections4-4.3.jar;F:/poi-4.1.0/lib/commons-compress-1.18.jar;\
                                                    F:/poi-4.1.0/lib/commons-logging-1.2.jar;F:/poi-4.1.0/lib/commons-math3-3.6.1.jar;F:/poi-4.1.0/lib/jaxb-api-2.3.0.jar;F:/poi-4.1.0/lib/jaxb-core-2.3.0.1.jar;\
                                                    F:/poi-4.1.0/lib/jaxb-impl-2.3.0.1.jar;F:/poi-4.1.0/lib/junit-4.12.jar;F:/poi-4.1.0/lib/log4j-1.2.17.jar;F:/poi-4.1.0/ooxml-lib/curvesapi-1.06.jar;F:/poi-4.1.0/ooxml-lib/xmlbeans-3.1.0.jar;";
    options[2].optionString = "-verbose:NONE";


    vm_args.version = JNI_VERSION_1_8;
    vm_args.nOptions = 3;
    vm_args.options = options;
    vm_args.ignoreUnrecognized = JNI_TRUE;

    // Load jvm.dll 
    DWORD dwErr1 = GetLastError();
    HINSTANCE hInstance = LoadLibrary("C:\\Program Files (x86)\\Java\\jdk1.8.0_211\\jre\\bin\\client\\jvm.dll");
    DWORD dwErr = GetLastError();
    if (hInstance == NULL)
        return false;
    _CreateJavaVM m_CreateJavaVM = (_CreateJavaVM)GetProcAddress(hInstance, "JNI_CreateJavaVM");

    res = (*m_CreateJavaVM)(&jvm, (void**)&env, &vm_args);
    if (res < 0)
        return -1;

    // Find the class  
    jclass XWPFDocument = env->FindClass("org/apache/poi/xwpf/usermodel/XWPFDocument");
    jclass XWPFParagraph = env->FindClass("org/apache/poi/xwpf/usermodel/XWPFParagraph");
    jclass OPCPackage = env->FindClass("org/apache/poi/openxml4j/opc/OPCPackage");
    jclass XWPFRun = env->FindClass("org/apache/poi/xwpf/usermodel/XWPFRun");
    jclass FileInputStream = env->FindClass("java/io/FileInputStream");
    jclass FileOutputStream = env->FindClass("java/io/FileOutputStream");
    jclass InputStream = env->FindClass("java/io/InputStream");
    jclass POIXMLDocument = env->FindClass("org/apache/poi/ooxml/POIXMLDocument");

    if (InputStream == NULL) {
        fprintf(stderr, "InputStream::FindClass failed\n");
    }
    else {
        fprintf(stderr, "InputStream::FindClass success\n");
    }
    if (FileOutputStream == NULL) {
        fprintf(stderr, "FileOutputStream::FindClass failed\n");
    }
    else {
        fprintf(stderr, "FileOutputStream::FindClass success\n");
    }
    //获取方法FileInputStream的ID
    jmethodID streammid = env->GetMethodID(FileInputStream, "<init>", "(Ljava/lang/String;)V");
    if (streammid == 0) {
        fprintf(stderr, "FileInputStream::GetMethodID failed\n");
        return -1;
    }
    else {
        fprintf(stderr, "FileInputStream::GetMethodID success\n");
    }
    jstring strPath2 = stoJstring(env, "F:/CallPoi.docx");
    jobject fileStreamObj = env->NewObject(FileInputStream, streammid, strPath2);
    if (fileStreamObj == NULL) {
        fprintf(stderr, "fileStreamObj failed\n");
        jvm->DestroyJavaVM();
        fprintf(stdout, "Java VM destory.\n");
        return -1;
    }
    else {
        fprintf(stderr, "StreamObj success\n");
    }
   // jobject inStreamObj = env->NewObject(InputStream, streammid, strPath2);

    //获取方法createParagraph的ID
    jmethodID mid = env->GetMethodID(XWPFDocument, "createParagraph", "()Lorg/apache/poi/xwpf/usermodel/XWPFParagraph;");
    //if (mid == 0) {
    //    fprintf(stderr, "createParagraph::GetMethodID failed\n");
    //    return -1;
    //}
    //else {
    //    fprintf(stderr, "createParagraph::GetMethodID success\n");
    //}

    //获取方法XWPFDocument构造ID
    jmethodID gzmid = env->GetMethodID(XWPFDocument, "<init>", "(Ljava/io/InputStream;)V");
    if (env->ExceptionCheck()) {
        // 检查JNI调用是否有引发异常
        env->ExceptionDescribe();
        env->ExceptionClear(); // 清除引发的异常,在Java层不会打印异常的堆栈信息
        env->ThrowNew(env->FindClass("java/lang/Exception"), "JNI抛出的异常!");
        return -1;
    }

    //创建一个文件包
    jobject packageObj = createOPCPackage(env, "F:/callPoiOpreate.docx");

    //新建一个文档  
    jobject docxObj = env->NewObject(XWPFDocument, gzmid, fileStreamObj);
    //创建一个段落  
    jobject paragraphObj = (jobject)env->CallObjectMethod(docxObj, mid);
    jmethodID setTextId = env->GetMethodID(XWPFRun, "setText", "(Ljava/lang/String;)V");

    //一个XWPFRun代表具有相同属性的一个区域。  
    jmethodID createRunId = env->GetMethodID(XWPFParagraph, "createRun", "()Lorg/apache/poi/xwpf/usermodel/XWPFRun;");
    if (env->ExceptionCheck()) {
        // 检查JNI调用是否有引发异常
        env->ExceptionDescribe();
        env->ExceptionClear(); // 清除引发的异常,在Java层不会打印异常的堆栈信息
        env->ThrowNew(env->FindClass("java/lang/Exception"), "JNI抛出的异常!");
        return -1;
    }

    jobject XWPFRunObj = (jobject)env->CallObjectMethod(paragraphObj, createRunId);
    if (XWPFRunObj == NULL) {
        fprintf(stderr, "paragraphObj  CallObjectMethod failed\n");
        jvm->DestroyJavaVM();
    }
    else {
        fprintf(stderr, "paragraphObj CallObjectMethod success\n");
    }

    //设置文档内容
    jstring textStr = stoJstring(env, "222223333 hello"); 
    env->CallObjectMethod(XWPFRunObj, setTextId, textStr);

    if (XWPFRunObj == NULL) {
        fprintf(stderr, "paragraphObj failed\n");
        jvm->DestroyJavaVM();
    }
    else {
        fprintf(stderr, "3333 succcess\n");
    }
    



    jmethodID writemid = env->GetMethodID(XWPFDocument, "write", "(Ljava/io/OutputStream;)V");

    if (env->ExceptionCheck()) {
        // 检查JNI调用是否有引发异常
        env->ExceptionDescribe();
        env->ExceptionClear(); // 清除引发的异常,在Java层不会打印异常的堆栈信息
        env->ThrowNew(env->FindClass("java/lang/Exception"), "JNI抛出的异常!");
        return -1;
    }
    fprintf(stdout, "writemid success.\n");

    jstring strsavePath2 = stoJstring(env, "F:/CallPoi.docx");
    jmethodID FileOutputStreammid = env->GetMethodID(FileOutputStream, "<init>", "(Ljava/lang/String;)V");

    jobject fileoutStreamObj = env->NewObject(FileOutputStream, FileOutputStreammid, strsavePath2);

    env->CallObjectMethod(docxObj, writemid, fileoutStreamObj);
    if (env->ExceptionCheck()) {
        // 检查JNI调用是否有引发异常
        env->ExceptionDescribe();
        env->ExceptionClear(); // 清除引发的异常,在Java层不会打印异常的堆栈信息
        env->ThrowNew(env->FindClass("java/lang/Exception"), "JNI抛出的异常!");
        return -1;
    }
    jmethodID closemid = env->GetMethodID(XWPFDocument, "close", "()V");
    env->CallObjectMethod(docxObj, closemid);

    /*释放虚拟机资源*/
    jvm->DestroyJavaVM();
    FreeLibrary(hInstance);
    return 0;
}


其中options[1].optionString = "-Djava.class.path=需要改为自己下载的poi的jar包路径,HINSTANCE hInstance = LoadLibrary(“C:\Program Files (x86)\Java\jdk1.8.0_211\jre\bin\client\jvm.dll”);需要改为自己的java下的路径。可以在新的文本中写入2222222.

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值