JAVA文件搜索过程中如何得到各种文件内容(office文件,PDF,邮件,mht,思维导图等)
现在流行的搜索引擎Lucene, Elasticsearch处理文件搜索时一般使用 tika,使用tika 处理文件正文搜索还好,但搜索结果显示正文等操作不是很方便,并且tika提取正文的速度比较慢。老版本还有很多外部依赖程序,安全性不好。
笔者给大家介绍一款调用方便,提取文件正文速度快,开发方便的组件供大家参考。
“Graccvs正文提取组件”全部用go语言实现,不依赖外部工具,效率高,安全性非常好。可以直接在操作系统上开发使用,不要求JAVA等其他环境支持,而且从设计上避免了环境依赖或者解析器框架带来的占用CPU过高和安全性问题。组件提取文本速度快,质量高,跨平台,支持多任务并发,开发简单成本低。提供多种语言接口及使用示例。
“Graccvs正文提取组件”支持很多文件格式:
A: pdf文件
B: office word文件 ".doc", ".odt", ".docx", ".dotm", ".docm"
C: wps文档 ".wps"
D: office excel文件 ".xls", ".xlsx", ".xlsm", ".xltm"
E: wps表格 ".et"
F: office powerPoint文件 ".ppt", ".pptx", ".potm", ".pptm", ".ppsm"
G: wps演示 ".dps"
H:开放文档格式 ".ofd", 注:常见于“电子发票版式文件”
I:富文本类型 ".rtf"
J: HTML页面文件 ".html", ".htm", ".mht", ".mhtml"
K:邮件格式文件 ".eml", 注:默认提取前5个附件
L:部分思维导图格式文件 ".emmx", "xmind", "gmind"
M: UTF8编码, Unicode编码, Ansi编码的文本文件,
".txt", ".c", ".h", ".cpp", ".m", ".asp", ".aspx", ".cs", ".pas",
".php", ".vb", ".bas", ".js", ".css", ".java", ".jsp", ".go",
".pl", ".perl", ".ps", ".py", ".python", ".sql", ".rs", ".dart"
注:可以在配置文件中增加纯文本文件后缀
N:帮助文件 “*.chm",注:此格式仅限Windows平台
O:压缩文件 ".zip", 注:默认提取前5个文件
以下是使用Eclipse开发工具,Java调用动态链接库示例:
调用过程:1:创建JAVA工程。2:工程导入调用DLL的扩展包Native(jna-jpms-5.9.0.jar 和 jna-platform-jpms-5.9.0.jar)。3:拷贝 graccvs64.dll到工程中,LibGraccvs.java单元修改DLL位置(默认在exe输出位置)。4:实现提取文件正文函数,点击这里查看DLL函数详细说明。5:点击这里下载完整工程包,这里下载最新DLL文件。
主要代码单元LibGraccvs.java (函数的定义):
package graccvsDLL;
//
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
//
public interface LibGraccvs extends Library {
//默认64位系统,32位DLL或者接口最新DLL查看官网
@SuppressWarnings("deprecation")
LibGraccvs INSTANCE = (LibGraccvs) Native.loadLibrary("graccvs64.dll", LibGraccvs.class);
//----------------------以下为函数说明----------------------
// 加载DLL,设置动态库需要的临时文件夹,且对此文件夹要有读写权限
void Load(Pointer tempDir);
//注册软件:
int Auth(Pointer corp, Pointer licText);
// 提供文件正文,并保存到目标文件
// inFilePtr输入文件地址, outFilePtr为TXT目标文件文件地址
int ToTextFile(Pointer inFilePtr, Pointer outFilePtr);
//其他一个文件的正文,返回UTF-8字符串指针
//注意,调用此函数需要使用FreeString释放指针内存
Pointer ToString(Pointer inFilePtr);
//得到最后错误日志
Pointer LastErr();
//释放ToString函数返回的指针内存
void FreeString(Pointer ptr);
// 提取Http/Https文件,返回字符串数据指针
// url=Http/Https地址
// fileExt=文件类型(比如:".pdf"),
// timeout=超时设置,超过此数值系统终止下载文件。单位为毫秒,默认为0(等待文件下载直到完成)
// httpParams=JSON格式header数据和cookie数据,默认为空
// 返回UTF-8编码字符串数据指针(此指针需要使用FreeString函数释放内存)
Pointer HttpToString(Pointer url, Pointer fileExt, int timeout, Pointer httpParams);
// 下载Http文件,并提取文本,保存到目标文件u
// outfile为TXT目标文件文件地址,其他参数和HTTPTOSTRING参数相同
int HttpToTextFile(Pointer url, Pointer fileExt, Pointer outfile, int timeout, Pointer httpParams);
//---------------------异步批量处理相关函数---------------------
// 文件提取异步任务, inFilePtr输入文件地址, outTxtFilePtr为TXT目标文件文件
// 如果提取某个文件错误,则 结果文本的内容如下格式: @ErrCode:错误代码, ErrMessage:错误提示
void AddTask(Pointer inFilePtr, Pointer outTxtFilePtr);
// 异步提取Http文件任务,参数同 HttpToTextFile 函数
void AddHttpTask(Pointer url, Pointer fileExt, Pointer outTxtFile, int timeout, Pointer httpParams);
// 开始执行异步任务,返回值=1开始执行, 其他值未识别
// =2 免费版不支持此功能,=3 没有可以执行的任务 ,=4 当前任务未完成
int AsyncStart();
// 停止任务
void AsyncStop();
// 一直等待,直到全部异步任务结束
void AsyncWait();
// 得到执行异步任务的状态, =0 没开始, =1 正在处理中,=2 已中断, =99 处理完成
int AsyncState();
// 设置执行异步任务的并发数量(不大于软件授权数量),返回并发数量
int AsyncMaxProcs(int num);
//---------------------异步批量处理相关函数---------------------
//程序结束前调用此函数,否则释放DLL会发生错误
void Unload();
}
主要代码单元TestMain.java (提取文件正文测试):
package graccvsDLL;
//
import java.io.UnsupportedEncodingException;
import java.util.*;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
//
public class TestMain {
public enum DllErrCode
{
TFE_OK,
TFE_UNKNOW,
TFE_FILE_NOTEXIST,
TFE_SAVE_ERROR,
TFE_OUTSIZE,
TFE_UNSUPPORTED ,
TFE_ERROR_INTERFACE ,
TFE_HTTP_ERR,
TFE_HTTP_FILE_NULL ,
TFE_LICENCE_ERR;
}
// 根据错误类型返回错误信息
public static String codeText(DllErrCode code)
{
switch (code)
{
case TFE_OK:
return "ok";
case TFE_UNKNOW:
return "未知错误";
case TFE_FILE_NOTEXIST:
return "提取源文件不存在";
case TFE_SAVE_ERROR:
return "保存目标文件失败";
case TFE_OUTSIZE:
return "提取的源文件超出设置的大小范围";
case TFE_UNSUPPORTED:
return "不支持的提取文件格式";
case TFE_ERROR_INTERFACE:
return "得到接口失败";
case TFE_HTTP_ERR :
return "HTTP下载文件失败";
case TFE_HTTP_FILE_NULL :
return "HTTP文件为空";
case TFE_LICENCE_ERR:
return "软件许可错误";
default:
return "未知错误2";
}
}
//字符串转指针
public static Pointer getUtf8Pointer(String str){
try {
byte[] data = str.getBytes("UTF-8");
Pointer p = new Memory(data.length + 1);
p.write(0, data, 0, data.length);
p.setByte(data.length, (byte)0);
return p;
}catch (UnsupportedEncodingException e) {
return null;
}
}
//utf8指针转换为字符串
public static String utf8pointerToString(Pointer p){
String str = p.getString(0);
try {
return new String(str.getBytes(), "UTF-8");
}catch (UnsupportedEncodingException e){
return str;
}
}
// ------------------------提取正文并保存为文本文件------------------------
public static void testToTextFile(){
Pointer prtInFile = getUtf8Pointer("test\\graccvs文件正文提取接口.pdf");
Pointer prtOutFile = getUtf8Pointer("test\\grcv001.txt");
//
int r = LibGraccvs.INSTANCE.ToTextFile(prtInFile, prtOutFile);
DllErrCode code = DllErrCode.values()[r];
if (code != DllErrCode.TFE_OK)
{
// 得到错误方式1: 根据R值调用函数ErrText得到具体错误信息, 此方式速度快
String err = codeText(code);
System.out.println("error from code:" + err);
// 方式2:调用DLL函数,得到具体错误信息, 此方式错误信息更加准确
Pointer p = LibGraccvs.INSTANCE.LastErr();
String err2 = utf8pointerToString(p);
System.out.println("error from dll lastErr:" + err2);
}
System.out.println("to text ok!");
}
// ------------------------提取正文,返回字符串指针------------------------
public static void testToString(){
Pointer prtInFile = getUtf8Pointer("test\\简可信模板OCR识别工具帮助.docx");
Pointer prtOutStr = LibGraccvs.INSTANCE.ToString(prtInFile);
try
{
String s = utf8pointerToString(prtOutStr);
System.out.println(s);
}
finally
{
LibGraccvs.INSTANCE.FreeString(prtOutStr); //调用此函数释放字符串内存,否则会导致内存泄漏
}
}
// ------------------------HTTP提取正文并保存为文本文件------------------------
public static void testHttpToTextFile()
{
Pointer prtUrl = getUtf8Pointer("https://www.gaya-soft.cn/dfs/v2/简可信模板OCR识别工具帮助.docx");
Pointer prtExt = getUtf8Pointer(".docx");
Pointer prtOutFile = getUtf8Pointer("test\\grcv002.txt");
// 调用DLL函数得到文件正文
int r = LibGraccvs.INSTANCE.HttpToTextFile(prtUrl, prtExt, prtOutFile, 0, null);
DllErrCode code = DllErrCode.values()[r];
//TFE_OK为提取完成,其他code调用codeText返回相同错误
if (code != DllErrCode.TFE_OK)
{
System.out.println("error from code, " + codeText(code));
}
else
{
System.out.println("testHttpToTextFile end");
}
}
// ------------------------HTTP提取正文,返回字符串指针------------------------
public static void testHttpToString()
{
Pointer prtUrl = getUtf8Pointer("https://www.gaya-soft.cn/dfs/v2/graccvs文件正文提取接口.pdf");
Pointer prtExt = getUtf8Pointer(".pdf");
String params = "{\"headers\":[{\"client_id\": \"g01x9\"}, {\"client_secret\": \"e23c89cc9fe\"}], \"cookies\":[{\"name\": \"ga\", \"value\": \"1020\", \"expires\":36000000, \"path\": \"/\"}]}";
Pointer prtParams = getUtf8Pointer(params);
int timeout = 60 * 1000; //超时设置,单位毫秒, 默认为0
//
Pointer prtOutStr = LibGraccvs.INSTANCE.HttpToString(prtUrl, prtExt, timeout, prtParams);
try
{
String s = utf8pointerToString(prtOutStr);
System.out.println(s);
}
finally
{
LibGraccvs.INSTANCE.FreeString(prtOutStr); // 务必调用函数释放字符串内存
}
}
// ---------------异步批量文件提取,适合多线程处理很多文件---------------
// 文件提取任务
public static void asyncAddTask()
{
// -----可以增加N个任务
Pointer prtInFile = getUtf8Pointer("test\\graccvs文件正文提取接口.pdf");
Pointer prtOutFile = getUtf8Pointer("test\\asyncOut001.txt");
LibGraccvs.INSTANCE.AddTask(prtInFile, prtOutFile); // 一个文件任务
Pointer prtInFile2 = getUtf8Pointer("test\\Adobe Intro.ofd");
Pointer prtOutFile2 = getUtf8Pointer("test\\asyncOut002.txt");
LibGraccvs.INSTANCE.AddTask(prtInFile2, prtOutFile2); // 一个文件任务
}
// Http文件提取任务
public static void asyncAddHttpTask()
{
// 可以增加N个任务
Pointer prtUrl = getUtf8Pointer("https://www.gaya-soft.cn/dfs/v2/简可信模板OCR识别工具帮助.docx");
Pointer prtExt = getUtf8Pointer(".docx");
Pointer prtOutFile = getUtf8Pointer("test\\asyncOut003.txt");
int timeout = 90 * 1000; //超时设置,单位毫秒, 默认为0
LibGraccvs.INSTANCE.AddHttpTask(prtUrl, prtExt, prtOutFile, timeout, null);
}
// 方式1:开始任务,等待全部任务完成
public static void asyncRun1()
{
// 开始任务
int r = LibGraccvs.INSTANCE.AsyncStart();
if (r == 1){
LibGraccvs.INSTANCE.AsyncWait(); // 等待任务全部结束
System.out.println("方式1 -- 任务完成");
}else if (r == 2){
System.out.println("免费版不支持此功能");
}else if (r == 3){
System.out.println("没有可以执行的任务");
}else if (r == 4){
System.out.println("当前任务未完成");
}
}
// 方式2:判断执行情况,超时退出,主动结束任务
public static void asyncRun2()
{
// 开始任务
boolean isOver = false;
int r = LibGraccvs.INSTANCE.AsyncStart();
if (r == 1){
Date startDt = new Date();
// 5分钟后结束任务
while((new Date()).getTime() - startDt.getTime() < 5 * 60 * 1000){
// 判断任务情况, =0 没开始, =1 正在处理中,=2 已中断, =99 处理完成
int x = LibGraccvs.INSTANCE.AsyncState();
if (x == 1){
try
{
Thread.sleep(500);
}
catch(InterruptedException e)
{
}
}else if (x == 99){
isOver = true; // 处理完成
break;
}else{
break;
}
}
//
if (!isOver){
LibGraccvs.INSTANCE.AsyncStop(); // 结束任务
}
System.out.println("方式2 -- 任务完成");
}else if (r == 2){
System.out.println("免费版不支持此功能");
}else if (r == 3){
System.out.println("没有可以执行的任务");
}else if (r == 4){
System.out.println("当前任务未完成");
}
}
public static void asyncTest()
{
//
LibGraccvs.INSTANCE.AsyncMaxProcs(8); // 同时运行8个任务
//
asyncAddTask(); // 文件提取任务
asyncAddHttpTask(); // Http文件提取任务
// 执行任务--方式1
asyncRun1();
// 执行任务--方式2
asyncAddTask();
asyncAddHttpTask();
asyncRun2();
}
// ---------------异步批量文件提取,适合多线程处理很多文件---------------
public static void main(String[] args) {
Pointer prtPath = getUtf8Pointer("test");
// 提取文本需要的临时文件夹,且对此文件夹要有读写权限
LibGraccvs.INSTANCE.Load(prtPath);
// 设置软件许可,免费版都为空
Pointer corp = getUtf8Pointer("gaya-soft.cn");
Pointer licTxt = getUtf8Pointer("");
LibGraccvs.INSTANCE.Auth(corp, licTxt);
// 提取正文并保存为文本文件
testToTextFile(); //
// 提取正文,返回字符串指针
testToString();
// 提取HTTP提取正文, 并保存为文本文件
testHttpToTextFile();
// 提取HTTP提取正文, 返回字符串指针
testHttpToString();
// 异步批量文件提取测试
asyncTest();
//
LibGraccvs.INSTANCE.Unload();
//
String s2 = "over!";
System.out.println(s2);
}
}