2011-01-12 3 views
5

Ho il codice per copiare un file in un'altra posizione.Errore con NIO durante il tentativo di copiare file di grandi dimensioni

public static void copyFile(String sourceDest, String newDest) throws IOException { 

    File sourceFile = new File(sourceDest); 
    File destFile = new File(newDest); 
    if (!destFile.exists()) { 
     destFile.createNewFile(); 
    } 

    FileChannel source = null; 
    FileChannel destination = null; 
    try { 
     source = new FileInputStream(sourceFile).getChannel(); 
     destination = new FileOutputStream(destFile).getChannel(); 
     destination.transferFrom(source, 0, source.size()); 
    } finally { 
     if (source != null) { 
      source.close(); 
     } 
     if (destination != null) { 
      destination.close(); 
     } 
    } 

} 
} 

Durante la copia di piccoli blocchi, ad esempio 300-400 Mb, tutto funziona come per magia. Ma quando ho provato a copiare un file della dimensione di 1.5 Gb non è riuscito. Lo stack è:

run: 12.01.2011 11:16:36 FileCopier main SEVERE: Exception occured while copying file. Try again. java.io.IOException: Map failed at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:748) at sun.nio.ch.FileChannelImpl.transferFromFileChannel(FileChannelImpl.java:527) at sun.nio.ch.FileChannelImpl.transferFrom(FileChannelImpl.java:590) at FileCopier.copyFile(FileCopier.java:64) at FileCopier.main(FileCopier.java:27) Caused by: java.lang.OutOfMemoryError: Map failed at sun.nio.ch.FileChannelImpl.map0(Native Method) at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:745) ... 4 more BUILD SUCCESSFUL (total time: 0 seconds)

Non ho lavorato con NIO da vicino. Mi potrebbe aiutare? Grazie mille in anticipo.

+0

Provare con Files.copy http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/io/Files.html se funziona ha un look-see in src – oluies

+0

Grazie. Ma preferirei non utilizzare le librerie di terze parti in questo caso specifico. –

risposta

5

Penso che potresti essere stato colpito da uno old bug che si è già verificato qualche tempo fa. Non stavo cercando di copiare un file, ma piuttosto di cercare attraverso un file mappato in memoria che ha fallito pure. Per me la soluzione è cercare il file in un ciclo e richiedere il GC e finalizers da eseguire ogni tanto.

La memoria mappata ByteBuffers rilascia la mappatura nel finalizzatore e fa spazio a nuovi mapping. Questo è molto brutto, ma almeno funziona. Speriamo che abbiano fatto qualcosa al riguardo nella prossima iterazione di NIO.

+1

Ho trovato una soluzione. Grazie per l'intuizione. http://snippets.dzone.com/posts/show/4946 –

+0

Sì, in realtà hanno risolto il bug in JRE 1.7 (Ho controllato in 1.7.0_51) –

2

Si sta mappando la memoria di un file ma lo spazio di indirizzo della memoria è limitato in una JVM a 32 bit (che presumo si stia utilizzando) quindi il metodo della mappa non funziona. Non penso che sia possibile mappare più di 1,3-1,4 GB di dati del disco. Quale dimensione dell'heap stai usando?

È possibile provare a ridurre le dimensioni dell'heap o utilizzare un JRE a 64 bit. In alternativa, non leggere il file mappandolo in memoria utilizzando NIO. Invece, utilizzare il modo tradizionale di un lettore e uno scrittore bufferizzati per leggere e scrivere dati da un file all'altro.

+0

Grazie, ho deciso di attenermi a NIO, semplicemente usando un approccio iterativo con un buffer della dimensione di 64 Mb. –