我们知道java里面File对象既可以表示目录也可以表示文件。
如果我想得到某个目录下的所有文件那么只需要一行代码就可以了。
File files[] = new File(".").listFiles();
如果目录下的文件过多,一般不会这样的。如果达到一定数目,那么这个执行这个方法时,可能导致内存溢出的异常。因为jdk是把该目录的所有文件都放到数组里面了,数组过大,栈空间不够了。
我在linux上做的测试,疯狂创建了很多文件,就导致了这样的结果。
此时如果我们用c来遍历该目录,c语言是移动指针的方式来做的,速度非常快。代码也非常简单。
但是这个过程中如果将文件删除此时性能急剧下降,相差2~3个数量级。因为在移除文件的时候数据库结构(Tree or Link)要不断的重新组合,所以性能急剧下降。
起初没有注意到这个问题,因为我是用jni调用的,调试时候发现listfile方法非常慢,因为我处理完文件对文件进行了删除。
Java代码:
public class FileList{
public static native String[] list(String path,int len);
static native final void initialize();
public static native final void destroy();
static{
try{
System.loadLibrary("cfilelist");
initialize();
}catch(Exception ex){}
}
}
FileList.h代码略
$>javah FileList
就可以产生
dirlist.c代码
#include<unistd.h>
#include<stdio.h>
#include<dirent.h>
#include<sys/stat.h>
#include<stdlib.h>
#include<string.h>
#include "FileList.h"
static jclass string_class;
void jni_log(const char *str){
}
JNIEXPORT void JNICALL Java_FileList_initialize
(JNIEnv *env, jclass jcls){
jclass jstring_cls;
jstring_cls=(*env)->FindClass(env,"java/lang/String");
if(jstring_cls)
{
string_class=(*env)->NewGlobalRef(env,jstring_cls);
}
}
JNIEXPORT void JNICALL Java_FileList_destroy
(JNIEnv *env, jclass jcls){
(*env)->DeleteGlobalRef(env, string_class);
}
JNIEXPORT jobjectArray JNICALL Java_FileList_list
(JNIEnv *env, jclass jcls, jstring jstrdir, jint jfcount){
int f_count;
jobjectArray jresult;
DIR *pDir;
char absPath[255];
struct dirent *entry;
struct stat statbuf;
char *p_ch;
const char *dir;
if(string_class==NULL){
jni_log("string_class==NULL");
return NULL;
}
dir=(*env)->GetStringUTFChars(env,jstrdir,0);
if(dir==NULL)
{
jni_log("dir==NULL");
return NULL;
}
jresult=(*env)->NewObjectArray(env,(jsize)jfcount,string_class,NULL);
if(jresult==NULL){
jni_log("jresult==null");
return NULL;
}
f_count=0;
if((pDir = opendir(dir)) == NULL){
jni_log("open dir = null");
jni_log(dir);
return NULL;
}
chdir(dir);
while((entry = readdir(pDir)) != NULL){
lstat(entry->d_name,&statbuf);
if(S_ISDIR(statbuf.st_mode)) continue; //if(strcmp(entry->d_name,".")==0||strcmp(entry->d_name,"..")==0)continue;
strcpy(absPath,dir);
strcat(absPath,"/");
strcat(absPath,entry->d_name);
jstring jfilestr=(*env)->NewStringUTF(env,absPath);
(*env)->SetObjectArrayElement(env,jresult,(jsize)f_count,jfilestr);
f_count++;
if(f_count>=jfcount)break;
}
closedir(pDir);
chdir("..");
(*env)->ReleaseStringUTFChars(env,jstrdir,dir);
return jresult;
}