2009-06-30 15 views
54

Tengo que escribir datos enormes en el archivo de texto [csv]. Usé BufferedWriter para escribir los datos y me tomó alrededor de 40 segundos escribir 174 mb de datos. ¿Es esta la velocidad más rápida que Java puede ofrecer?Forma más rápida de escribir datos enormes en el archivo de texto Java

bufferedWriter = new BufferedWriter (new FileWriter ("fileName.csv")); 

Nota: Estos incluyen 40 segundos el tiempo de la iteración y ir a buscar los registros del conjunto de resultados también. :). 174 mb es para 400000 filas en el conjunto de resultados.

+3

casualidad no tener antivirus activo en la máquina donde se ejecuta este código? –

Respuesta

87

Usted podría intentar eliminar el BufferedWriter y simplemente usar el FileWriter directamente. En un sistema moderno, hay muchas posibilidades de que simplemente esté escribiendo en la memoria caché de la unidad de todos modos.

Me toma en el rango de 4-5 segundos escribir 175MB (4 millones de cadenas) - esto es en un Dell de doble núcleo a 2.4GHz con Windows XP con un disco Hitachi de 80GB, 7200-RPM.

¿Puede aislar la cantidad de tiempo que es la recuperación de registros y cuánto se está escribiendo?

import java.io.BufferedWriter; 
import java.io.File; 
import java.io.FileWriter; 
import java.io.IOException; 
import java.io.Writer; 
import java.util.ArrayList; 
import java.util.List; 

public class FileWritingPerfTest { 


private static final int ITERATIONS = 5; 
private static final double MEG = (Math.pow(1024, 2)); 
private static final int RECORD_COUNT = 4000000; 
private static final String RECORD = "Help I am trapped in a fortune cookie factory\n"; 
private static final int RECSIZE = RECORD.getBytes().length; 

public static void main(String[] args) throws Exception { 
    List<String> records = new ArrayList<String>(RECORD_COUNT); 
    int size = 0; 
    for (int i = 0; i < RECORD_COUNT; i++) { 
     records.add(RECORD); 
     size += RECSIZE; 
    } 
    System.out.println(records.size() + " 'records'"); 
    System.out.println(size/MEG + " MB"); 

    for (int i = 0; i < ITERATIONS; i++) { 
     System.out.println("\nIteration " + i); 

     writeRaw(records); 
     writeBuffered(records, 8192); 
     writeBuffered(records, (int) MEG); 
     writeBuffered(records, 4 * (int) MEG); 
    } 
} 

private static void writeRaw(List<String> records) throws IOException { 
    File file = File.createTempFile("foo", ".txt"); 
    try { 
     FileWriter writer = new FileWriter(file); 
     System.out.print("Writing raw... "); 
     write(records, writer); 
    } finally { 
     // comment this out if you want to inspect the files afterward 
     file.delete(); 
    } 
} 

private static void writeBuffered(List<String> records, int bufSize) throws IOException { 
    File file = File.createTempFile("foo", ".txt"); 
    try { 
     FileWriter writer = new FileWriter(file); 
     BufferedWriter bufferedWriter = new BufferedWriter(writer, bufSize); 

     System.out.print("Writing buffered (buffer size: " + bufSize + ")... "); 
     write(records, bufferedWriter); 
    } finally { 
     // comment this out if you want to inspect the files afterward 
     file.delete(); 
    } 
} 

private static void write(List<String> records, Writer writer) throws IOException { 
    long start = System.currentTimeMillis(); 
    for (String record: records) { 
     writer.write(record); 
    } 
    writer.flush(); 
    writer.close(); 
    long end = System.currentTimeMillis(); 
    System.out.println((end - start)/1000f + " seconds"); 
} 
} 
+2

@rozario cada llamada de escritura solo debe producir unos 175MB y luego eliminarse.si no, terminará con 175MB x 4 llamadas de escritura diferentes x 5 iteraciones = 3.5GB de datos. puede verificar el valor de retorno de file.delete() y si es falso, lanzar una excepción. –

+0

Observe que 'writer.flush()' no es necesario en este caso porque 'writer.close()' [vacía la memoria] (http://docs.oracle.com/javase/7/docs/api/java/io /BufferedWriter.html) implicity. Por cierto: las mejores prácticas recomiendan usar [try resource close] (https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html) en lugar de llamar explícitamente a 'close()'. –

+2

FWIW, esto fue escrito para Java 5, que al menos no estaba documentado al principio, y que no tenía try-with-resources. Probablemente podría usar la actualización. –

4

Su velocidad de transferencia probablemente no esté limitada por Java. En vez sospecharía (en ningún orden en particular)

  1. la velocidad de la transferencia de la base de datos
  2. la velocidad de transferencia al disco

Si usted lee el conjunto completo de datos y luego escribirlo en el disco, eso llevará más tiempo, ya que la JVM tendrá que asignar memoria, y la escritura del db rea/disk ocurrirá secuencialmente. En su lugar, escribiría en el escritor en el búfer por cada lectura que realice desde el DB, por lo que la operación será más cercana a una simultánea (no sé si lo está haciendo o no)

28

memoria, trate de archivos asignados (tarda 300 m/s para escribir 174MB en mi m/c, core 2 duo, 2,5 GB de RAM):

byte[] buffer = "Help I am trapped in a fortune cookie factory\n".getBytes(); 
int number_of_lines = 400000; 

FileChannel rwChannel = new RandomAccessFile("textfile.txt", "rw").getChannel(); 
ByteBuffer wrBuf = rwChannel.map(FileChannel.MapMode.READ_WRITE, 0, buffer.length * number_of_lines); 
for (int i = 0; i < number_of_lines; i++) 
{ 
    wrBuf.put(buffer); 
} 
rwChannel.close(); 
+0

¿qué significa aMessage.length() representar cuando estás instanciando el ByteBuffer? – Hotel

+2

Jut fyi, ejecutando esto en MacBook Pro (finales de 2013), 2.6 Ghz Core i7, con Apple 1tb SSD toma alrededor de 140ms por 185 meg (líneas = 4million) – Egwor

+0

¿de qué sirve el "number_of_lines"? –

14

sólo por el bien de las estadísticas :

La máquina es viejo Dell con el nuevo SSD

CPU: Intel Pentium D 2,8 GHz

SSD: Patriot Inferno 120 GB SSD

4000000 'records' 
175.47607421875 MB 

Iteration 0 
Writing raw... 3.547 seconds 
Writing buffered (buffer size: 8192)... 2.625 seconds 
Writing buffered (buffer size: 1048576)... 2.203 seconds 
Writing buffered (buffer size: 4194304)... 2.312 seconds 

Iteration 1 
Writing raw... 2.922 seconds 
Writing buffered (buffer size: 8192)... 2.406 seconds 
Writing buffered (buffer size: 1048576)... 2.015 seconds 
Writing buffered (buffer size: 4194304)... 2.282 seconds 

Iteration 2 
Writing raw... 2.828 seconds 
Writing buffered (buffer size: 8192)... 2.109 seconds 
Writing buffered (buffer size: 1048576)... 2.078 seconds 
Writing buffered (buffer size: 4194304)... 2.015 seconds 

Iteration 3 
Writing raw... 3.187 seconds 
Writing buffered (buffer size: 8192)... 2.109 seconds 
Writing buffered (buffer size: 1048576)... 2.094 seconds 
Writing buffered (buffer size: 4194304)... 2.031 seconds 

Iteration 4 
Writing raw... 3.093 seconds 
Writing buffered (buffer size: 8192)... 2.141 seconds 
Writing buffered (buffer size: 1048576)... 2.063 seconds 
Writing buffered (buffer size: 4194304)... 2.016 seconds 

Como podemos ver el método crudo es más lenta es la memoria intermedia.

+0

Sin embargo, el método de búfer se vuelve más lento cada vez que el tamaño del texto es más grande. – FSm

1

package all.is.well; 
 
import java.io.IOException; 
 
import java.io.RandomAccessFile; 
 
import java.util.concurrent.ExecutorService; 
 
import java.util.concurrent.Executors; 
 
import junit.framework.TestCase; 
 

 
/** 
 
* @author Naresh Bhabat 
 
* 
 
Following implementation helps to deal with extra large files in java. 
 
This program is tested for dealing with 2GB input file. 
 
There are some points where extra logic can be added in future. 
 

 

 
Pleasenote: if we want to deal with binary input file, then instead of reading line,we need to read bytes from read file object. 
 

 

 

 
It uses random access file,which is almost like streaming API. 
 

 

 
* **************************************** 
 
Notes regarding executor framework and its readings. 
 
Please note :ExecutorService executor = Executors.newFixedThreadPool(10); 
 

 
* \t for 10 threads:Total time required for reading and writing the text in 
 
*   :seconds 349.317 
 
* 
 
*   For 100:Total time required for reading the text and writing : seconds 464.042 
 
* 
 
*   For 1000 : Total time required for reading and writing text :466.538 
 
*   For 10000 Total time required for reading and writing in seconds 479.701 
 
* 
 
* 
 
*/ 
 
public class DealWithHugeRecordsinFile extends TestCase { 
 

 
\t static final String FILEPATH = "C:\\springbatch\\bigfile1.txt.txt"; 
 
\t static final String FILEPATH_WRITE = "C:\\springbatch\\writinghere.txt"; 
 
\t static volatile RandomAccessFile fileToWrite; 
 
\t static volatile RandomAccessFile file; 
 
\t static volatile String fileContentsIter; 
 
\t static volatile int position = 0; 
 

 
\t public static void main(String[] args) throws IOException, InterruptedException { 
 
\t \t long currentTimeMillis = System.currentTimeMillis(); 
 

 
\t \t try { 
 
\t \t \t fileToWrite = new RandomAccessFile(FILEPATH_WRITE, "rw");//for random write,independent of thread obstacles 
 
\t \t \t file = new RandomAccessFile(FILEPATH, "r");//for random read,independent of thread obstacles 
 
\t \t \t seriouslyReadProcessAndWriteAsynch(); 
 

 
\t \t } catch (IOException e) { 
 
\t \t \t // TODO Auto-generated catch block 
 
\t \t \t e.printStackTrace(); 
 
\t \t } 
 
\t \t Thread currentThread = Thread.currentThread(); 
 
\t \t System.out.println(currentThread.getName()); 
 
\t \t long currentTimeMillis2 = System.currentTimeMillis(); 
 
\t \t double time_seconds = (currentTimeMillis2 - currentTimeMillis)/1000.0; 
 
\t \t System.out.println("Total time required for reading the text in seconds " + time_seconds); 
 

 
\t } 
 

 
\t /** 
 
\t * @throws IOException 
 
\t * Something asynchronously serious 
 
\t */ 
 
\t public static void seriouslyReadProcessAndWriteAsynch() throws IOException { 
 
\t \t ExecutorService executor = Executors.newFixedThreadPool(10);//pls see for explanation in comments section of the class 
 
\t \t while (true) { 
 
\t \t \t String readLine = file.readLine(); 
 
\t \t \t if (readLine == null) { 
 
\t \t \t \t break; 
 
\t \t \t } 
 
\t \t \t Runnable genuineWorker = new Runnable() { 
 
\t \t \t \t @Override 
 
\t \t \t \t public void run() { 
 
\t \t \t \t \t // do hard processing here in this thread,i have consumed 
 
\t \t \t \t \t // some time and eat some exception in write method. 
 
\t \t \t \t \t writeToFile(FILEPATH_WRITE, readLine); 
 
\t \t \t \t \t // System.out.println(" :" + 
 
\t \t \t \t \t // Thread.currentThread().getName()); 
 

 
\t \t \t \t } 
 
\t \t \t }; 
 
\t \t \t executor.execute(genuineWorker); 
 
\t \t } 
 
\t \t executor.shutdown(); 
 
\t \t while (!executor.isTerminated()) { 
 
\t \t } 
 
\t \t System.out.println("Finished all threads"); 
 
\t \t file.close(); 
 
\t \t fileToWrite.close(); 
 
\t } 
 

 
\t /** 
 
\t * @param filePath 
 
\t * @param data 
 
\t * @param position 
 
\t */ 
 
\t private static void writeToFile(String filePath, String data) { 
 
\t \t try { 
 
\t \t \t // fileToWrite.seek(position); 
 
\t \t \t data = "\n" + data; 
 
\t \t \t if (!data.contains("Randomization")) { 
 
\t \t \t \t return; 
 
\t \t \t } 
 
\t \t \t System.out.println("Let us do something time consuming to make this thread busy"+(position++) + " :" + data); 
 
\t \t \t System.out.println("Lets consume through this loop"); 
 
\t \t \t int i=1000; 
 
\t \t \t while(i>0){ 
 
\t \t \t 
 
\t \t \t \t i--; 
 
\t \t \t } 
 
\t \t \t fileToWrite.write(data.getBytes()); 
 
\t \t \t throw new Exception(); 
 
\t \t } catch (Exception exception) { 
 
\t \t \t System.out.println("exception was thrown but still we are able to proceeed further" 
 
\t \t \t \t \t + " \n This can be used for marking failure of the records"); 
 
\t \t \t //exception.printStackTrace(); 
 

 
\t \t } 
 

 
\t } 
 
}

+0

Agregue un texto que explique por qué esta respuesta es mejor que otras respuestas. Tener comentarios en el código no es suficiente. –

+0

La razón por la que esto podría ser mejor: es un escenario en tiempo real y está en un ejemplo de estado de trabajo. Otros beneficios de esto, procesa la lectura, el procesamiento y la escritura de forma asíncrona ... Utiliza una apilación java eficiente (es decir, un archivo de acceso aleatorio que es seguro para hilos y múltiples hilos pueden leer y escribir en él simultáneamente). No causa sobrecarga de memoria en tiempo de ejecución, tampoco interrumpe el sistema ... es una solución multipropósito para hacer frente a la falla del procesamiento de registros que se puede rastrear en el hilo respectivo. Por favor, avíseme si puedo ayudar más. – RAM

+1

Gracias, esa es la información que su publicación necesitaba. Quizás considere agregarlo al cuerpo del mensaje :) –

Cuestiones relacionadas