Si tiene Java 1.5 o 1.6, desgranar comandos "dir" y analizar el flujo de salida estándar en Windows es un enfoque perfectamente aceptable. He utilizado este enfoque en el pasado para procesar unidades de red y, en general, ha sido mucho más rápido que esperar a que vuelva el método nativo java.io.File listFiles().
Por supuesto, una llamada JNI debería ser más rápida y potencialmente más segura que desgranar comandos "dir". El siguiente código JNI se puede usar para recuperar una lista de archivos/directorios utilizando la API de Windows. Esta función se puede refactorizar fácilmente en una nueva clase para que la persona que llama pueda recuperar rutas de archivos de forma incremental (es decir, obtener una ruta a la vez). Por ejemplo, puede refactorizar el código para llamar a FindFirstFileW en un constructor y tener un método separado para llamar a FindNextFileW.
JNIEXPORT jstring JNICALL Java_javaxt_io_File_GetFiles(JNIEnv *env, jclass, jstring directory)
{
HANDLE hFind;
try {
//Convert jstring to wstring
const jchar *_directory = env->GetStringChars(directory, 0);
jsize x = env->GetStringLength(directory);
wstring path; //L"C:\\temp\\*";
path.assign(_directory, _directory + x);
env->ReleaseStringChars(directory, _directory);
if (x<2){
jclass exceptionClass = env->FindClass("java/lang/Exception");
env->ThrowNew(exceptionClass, "Invalid path, less than 2 characters long.");
}
wstringstream ss;
BOOL bContinue = TRUE;
WIN32_FIND_DATAW data;
hFind = FindFirstFileW(path.c_str(), &data);
if (INVALID_HANDLE_VALUE == hFind){
jclass exceptionClass = env->FindClass("java/lang/Exception");
env->ThrowNew(exceptionClass, "FindFirstFileW returned invalid handle.");
}
//HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
//DWORD dwBytesWritten;
// If we have no error, loop thru the files in this dir
while (hFind && bContinue){
/*
//Debug Print Statment. DO NOT DELETE! cout and wcout do not print unicode correctly.
WriteConsole(hStdOut, data.cFileName, (DWORD)_tcslen(data.cFileName), &dwBytesWritten, NULL);
WriteConsole(hStdOut, L"\n", 1, &dwBytesWritten, NULL);
*/
//Check if this entry is a directory
if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
// Make sure this dir is not . or ..
if (wstring(data.cFileName) != L"." &&
wstring(data.cFileName) != L"..")
{
ss << wstring(data.cFileName) << L"\\" << L"\n";
}
}
else{
ss << wstring(data.cFileName) << L"\n";
}
bContinue = FindNextFileW(hFind, &data);
}
FindClose(hFind); // Free the dir structure
wstring cstr = ss.str();
int len = cstr.size();
//WriteConsole(hStdOut, cstr.c_str(), len, &dwBytesWritten, NULL);
//WriteConsole(hStdOut, L"\n", 1, &dwBytesWritten, NULL);
jchar* raw = new jchar[len];
memcpy(raw, cstr.c_str(), len*sizeof(wchar_t));
jstring result = env->NewString(raw, len);
delete[] raw;
return result;
}
catch(...){
FindClose(hFind);
jclass exceptionClass = env->FindClass("java/lang/Exception");
env->ThrowNew(exceptionClass, "Exception occured.");
}
return NULL;
}
Crédito: https://sites.google.com/site/jozsefbekes/Home/windows-programming/miscellaneous-functions
Incluso con este enfoque, todavía hay eficiencias que se pueden obtener. Si serializa la ruta a java.io.File, hay un enorme impacto en el rendimiento, especialmente si la ruta representa un archivo en una unidad de red. No tengo idea de qué hace Sun/Oracle bajo el capó, pero si necesita atributos de archivo adicionales a la ruta del archivo (por ejemplo, tamaño, fecha de modificación, etc.), he encontrado que la siguiente función JNI es mucho más rápida que crear una instancia de Java .io.Archivo objeto en una red de la ruta.
JNIEXPORT jlongArray JNICALL Java_javaxt_io_File_GetFileAttributesEx(JNIEnv *env, jclass, jstring filename)
{
//Convert jstring to wstring
const jchar *_filename = env->GetStringChars(filename, 0);
jsize len = env->GetStringLength(filename);
wstring path;
path.assign(_filename, _filename + len);
env->ReleaseStringChars(filename, _filename);
//Get attributes
WIN32_FILE_ATTRIBUTE_DATA fileAttrs;
BOOL result = GetFileAttributesExW(path.c_str(), GetFileExInfoStandard, &fileAttrs);
if (!result) {
jclass exceptionClass = env->FindClass("java/lang/Exception");
env->ThrowNew(exceptionClass, "Exception Occurred");
}
//Create an array to store the WIN32_FILE_ATTRIBUTE_DATA
jlong buffer[6];
buffer[0] = fileAttrs.dwFileAttributes;
buffer[1] = date2int(fileAttrs.ftCreationTime);
buffer[2] = date2int(fileAttrs.ftLastAccessTime);
buffer[3] = date2int(fileAttrs.ftLastWriteTime);
buffer[4] = fileAttrs.nFileSizeHigh;
buffer[5] = fileAttrs.nFileSizeLow;
jlongArray jLongArray = env->NewLongArray(6);
env->SetLongArrayRegion(jLongArray, 0, 6, buffer);
return jLongArray;
}
puede encontrar un ejemplo de trabajo completa de este enfoque basado en JNI en la biblioteca javaxt-core. En mis pruebas usando Java 1.6.0_38 con un host de Windows que golpea un recurso compartido de Windows, he encontrado este enfoque JNI aproximadamente 10 veces más rápido que llamar a java.io.File listFiles() o descascarar comandos "dir".
¿Cuál es su arquitectura de destino? ¿Necesita mantener la ejecución multiplataforma? –
Windows es el objetivo – Pyrolistical
Me doy cuenta de que esta es una pregunta muy antigua, pero para cualquiera que use el último JDK7, esta funcionalidad ahora está disponible a través de ['Files.newDirectoryStream()'] (http://docs.oracle.com /javase/7/docs/api/java/nio/file/Files.html#newDirectoryStream%28java.nio.file.Path%29) API en el paquete 'java.nio.file'. –