Android中使用jni调用第三方源码:grep(1)

来源:互联网 发布:linux 电源按钮 锁定 编辑:程序博客网 时间:2024/05/15 23:44

以前在Android中用jAVA实现了一个文件内容搜索的功能,对于大文件搜索简直是恶梦。抛开本身算法问题不谈,准备直接用jni调用linux中经常使用的grep,感谢开源软件带来的好处!

我需要的功能很简单,就是在一个文件中找到所有符合条件的字符串并打印它们的位置。这里使用了grep最初的版本grep 2.0,所有的源文件都在同一层目录。

1. 新建grep/jni目录,将所有*.c和*.h文件复制过去。

2. 修改grep.c文件,新建一个名为mysearch的函数,用于给jni层调用。

char* mysearch(argc, argv)     int argc;     char *argv[];{  char* search_result;  char *keys;  size_t keycc, oldcc, keyalloc;  int keyfound, count_matches, no_filenames, list_files, suppress_errors;  int opt, cc, desc, count, status;  FILE *fp;  extern char *optarg;  extern int optind;  int ii;  resultFP = fopen(argv[4],"a");  fprintf(resultFP, "%i\n", argc);  for(ii = 0; ii < argc; ii++)  {fprintf(resultFP, "%s\n", argv[ii]);   }  prog = argv[0];  if (prog && strrchr(prog, '/'))    prog = strrchr(prog, '/') + 1;  keys = NULL;  keycc = 0;  keyfound = 0;  count_matches = 0;  no_filenames = 0;  list_files = 0;  suppress_errors = 0;//  matcher = NULL;  matcher = "fgrep";//固定搜索  while ((opt = getopt(argc, argv, "0123456789A:B:CEFGVX:bce:f:hiLlnqsvwxy")) != EOF)    switch (opt)      {      case '0':      case '1':      case '2':      case '3':      case '4':      case '5':      case '6':      case '7':      case '8':      case '9':out_before = 10 * out_before + opt - '0';out_after = 10 * out_after + opt - '0';break;      case 'A':out_after = atoi(optarg);if (out_after < 0)  usage();break;      case 'B':out_before = atoi(optarg);if (out_before < 0)  usage();break;      case 'C':out_before = out_after = 2;break;      case 'E':if (matcher && strcmp(matcher, "egrep") != 0)  fatal("you may specify only one of -E, -F, or -G", 0);matcher = "posix-egrep";break;      case 'F':if (matcher && strcmp(matcher, "fgrep") != 0)  fatal("you may specify only one of -E, -F, or -G", 0);;matcher = "fgrep";break;      case 'G':if (matcher && strcmp(matcher, "grep") != 0)  fatal("you may specify only one of -E, -F, or -G", 0);matcher = "grep";break;      case 'V':fprintf(stderr, "%s\n", version);break;      case 'X':if (matcher)  fatal("matcher already specified", 0);matcher = optarg;break;      case 'b':out_byte = 1;break;      case 'c':out_quiet = 1;count_matches = 1;break;      case 'e':cc = strlen(optarg);keys = xrealloc(keys, keycc + cc + 1);if (keyfound)  keys[keycc++] = '\n';strcpy(&keys[keycc], optarg);keycc += cc;keyfound = 1;break;      case 'f':fp = strcmp(optarg, "-") != 0 ? fopen(optarg, "r") : stdin;if (!fp)  fatal(optarg, errno);for (keyalloc = 1; keyalloc <= keycc; keyalloc *= 2)  ;keys = xrealloc(keys, keyalloc);oldcc = keycc;if (keyfound)  keys[keycc++] = '\n';while (!feof(fp)       && (cc = fread(keys + keycc, 1, keyalloc - keycc, fp)) > 0)  {    keycc += cc;    if (keycc == keyalloc)      keys = xrealloc(keys, keyalloc *= 2);  }if (fp != stdin)  fclose(fp);/* Nuke the final newline to avoid matching a null string. */if (keycc - oldcc > 0 && keys[keycc - 1] == '\n')  --keycc;keyfound = 1;break;      case 'h':no_filenames = 1;break;      case 'i':      case 'y':/* For old-timers . . . */match_icase = 1;break;      case 'L':/* Like -l, except list files that don't contain matches.   Inspired by the same option in Hume's gre. */out_quiet = 1;list_files = -1;break;      case 'l':out_quiet = 1;list_files = 1;break;      case 'n':out_line = 1;break;      case 'q':out_quiet = 1;break;      case 's':suppress_errors = 1;break;      case 'v':out_invert = 1;break;      case 'w':match_words = 1;break;      case 'x':match_lines = 1;break;      default:usage();break;      }  if (!keyfound)    if (optind < argc)      {keys = argv[optind++];keycc = strlen(keys);      }    else      usage();  if (!matcher)    matcher = prog;  if (!setmatcher(matcher) && !setmatcher("default"))    abort();  (*compile)(keys, keycc);  if (argc - optind > 1 && !no_filenames)    out_file = 1;  status = 1;  if (optind < argc)//    while (optind < argc)      {desc = strcmp(argv[optind], "-") ? open(argv[optind], O_RDONLY) : 0;if (desc < 0)  {    if (!suppress_errors)      error(argv[optind], errno);  }else  {    filename = desc == 0 ? "(standard input)" : argv[optind];    count = grep(desc);    if (count_matches)      {if (out_file)  printf("%s:", filename);printf("%d\n", count);      }    if (count)      {status = 0;if (list_files == 1)  printf("%s\n", filename);      }    else if (list_files == -1)      printf("%s\n", filename);  }if (desc != 0)  close(desc);optind=argc;      }  else    {      filename = "(standard input)";      count = grep(0);      if (count_matches)printf("%d\n", count);      if (count){  status = 0;  if (list_files == 1)    printf("(standard input)\n");}      else if (list_files == -1)printf("(standard input)\n");    }  fclose(resultFP);}

2. 新建grepJni.c文件,用于调用grep.c中的mysearch方法,并给Java层提供名为grep的方法。内容如下:

#include <string.h>#include <jni.h>#include <dlfcn.h>#include <android/log.h>#include <stdlib.h>#define  LOG_TAG    "grepJni"#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)JNIEXPORT void JNICALL Java_com_lsj_TextSearch_grep(JNIEnv *env, jobject obj, jstring jtext, jstring jpath, jstring jlogpath){LOGI("open so success!");char* text = (*env)->GetStringUTFChars(env, jtext, NULL);char* path = (*env)->GetStringUTFChars(env, jpath, NULL);char* logpath = (*env)->GetStringUTFChars(env, jlogpath, NULL);char* sa[] = {"grep", "-b", text, path, logpath};mysearch(5,sa);}
3. 新建Android.mk文件:

#获取当前目录LOCAL_PATH := $(call my-dir)#清除一些变量include $(CLEAR_VARS)#要生成的库名LOCAL_MODULE    := grep#库对应的源文件LOCAL_SRC_FILES := alloca.c dfa.c grep.c obstack.c search.c getopt.c kwset.c regex.c grepJni.c#libtest.so需要引用的库libdl.so:加载动态函数需要,liblog.so 日志打印需要,默认是system/lib目录下LOCAL_LDLIBS := -ldl -llog #生成动态库libgrep.soinclude $(BUILD_SHARED_LIBRARY)
4. 编译生成so文件。

下载Android NDK,并将NDK加入环境变量。

在前面的grep目录下运行ndk-build,生成libgrep.so文件。将该文件复制到Android项目的libs/armeabi目录下。

4. 在Java中调用grep.so。

在com.lsj.TextSearch类(该类名必须与第2步中的com_lsj_TextSearch名称匹配)中,调用grep库。

载入动态库:

static {System.loadLibrary("grep");}
其中System.loadLibrary中的grep对应/libs/armeabi中的libgrep.so,Android后自动过滤前面的lib和后面的.so。

声明grep函数:

public native void grep(String text, String path, String logPath);
调用grep函数:

grep(searchText, filePath, logPath);

该函数作用是在filePath中搜索searchText字符串,并将搜索结果存放在logPath文件中。








0 0
原创粉丝点击