Pregunta

Tengo un archivo de tamaño 2 GB que contiene registros de estudiantes.Necesito encontrar estudiantes en función de ciertos atributos en cada registro y crear un nuevo archivo con los resultados.El orden de los estudiantes filtrados debe ser el mismo que en el archivo original.¿Cuál es la forma más eficiente y rápida de hacer esto utilizando la API y los subprocesos de Java IO sin tener problemas de memoria?El tamaño máximo de montón para JVM está establecido en 512 MB.

¿Fue útil?

Solución

  1. 2GB para un archivo es enorme, debe optar por un DB.
  2. Si realmente quieres usar API Java I/O, luego prueba esto: Manejo de grandes archivos de datos de manera eficiente con Java y esto: Tuning Java I/O Performance

Otros consejos

¿Qué tipo de archivo? Basado en texto, como CSV?

La forma más fácil sería hacer algo como Grep: leer el archivo Line by Line, analizar la línea, verificar su criterio de filtro, si coincide, generar una línea de resultados, luego vaya a la siguiente línea, hasta que el archivo esté listo. Esto es muy eficiente en la memoria, ya que solo tiene la línea actual (o un búfer un poco más grande) cargada al mismo tiempo. Su proceso necesita leer todo el archivo solo una vez.

No creo que varios hilos ayuden mucho. Haría las cosas mucho más complicadas, y dado que el proceso parece estar vinculado de todos modos, tratar de leer el mismo archivo con múltiples hilos probablemente no mejore el rendimiento.

Si encuentra que necesita hacer esto a menudo, y pasar por el archivo cada vez es demasiado lento, debe construir algún tipo de índice. La forma más fácil de hacerlo sería importar el archivo en un DB (puede ser primero un DB integrado como SQLite o HSQL).

No complicaría esto hasta que encuentre que la forma enorme no funciona para lo que necesita. Esencialmente solo necesitas:

  • Abra la transmisión de entrada a un archivo de 2 GB, recordando buffer (por ejemplo, envolviendo con BufferedInputStream)
  • Abra la transmisión de salida al archivo filtrado que va a crear
  • Lea el primer registro de la transmisión de entrada, mire cualquier atributo para decidir si lo "necesita"; Si lo hace, escríbelo al archivo de salida
  • Repita para los registros restantes

En uno de mis sistemas de prueba con hardware extremadamente modesto, BufferedInputStream alrededor de un FileInputStream fuera de la caja lee alrededor de 500 MB en 25 segundos, es decir, probablemente menos de 2 minutos para procesar su archivo de 2 GB, y el tamaño de búfer predeterminado es básicamente tan bueno como se vuelve (Ver el Tiempos BufferedInputStream Hice para más detalles). Me imagino que con el hardware de última generación es muy posible que el tiempo se reduzca a la mitad.

Ya sea que deba hacer mucho esfuerzo para reducir los 2/3 minutos o simplemente ir por un pequeño mientras esté esperando que se ejecute es una decisión que tendrá que tomar según sus requisitos. Creo que la opción de base de datos no le comprará mucho a menos que necesite realizar muchas ejecuciones de procesamiento diferentes en el mismo conjunto de datos (y hay otras soluciones a esto que no significan automáticamente la base de datos).

Creo que deberías usar mapeo de memoria Archivos. Esto lo ayudará a asignar el archivo más grande a una memoria más pequeña. Esto actuará como memoria virtual y, en lo que respecta al rendimiento, los archivos asignados son los más rápidos que la escritura/lectura de la transmisión.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top