2017-07-15 5 views
-1

J'utilise MappedByteBuffer pour écrire des enregistrements dans un fichier. Voici mon code. Il lance BufferOverflowException lorsque j'augmente le nombre de lignes à écrire. Cela fonctionne bien pour 10 millions numberOfRows. Si j'augmente numberOfRows à 100 millions, il lance BufferOverlowException !?MappedByteBuffer - BufferOverflowException

public static void writeOneFile() throws IOException{ 
    File file = File.createTempFile("outputfile", ".txt", new File("C:\\Data\\Output")); 
    //f.delete(); 
    RandomAccessFile fileAccess = new RandomAccessFile(file, "rw"); 
    FileChannel fileChannel = fileAccess.getChannel(); 

    long bufferSize = (long) (Math.pow(10240, 2));//(long)(Math.pow(30720, 2));//(long) (Math.pow(1024, 2));//(long)Integer.MAX_VALUE; 
    MappedByteBuffer mappedBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, bufferSize); 

    long startPosMappedBuffer = 0; 
    long million = 1000000; 
    long numberOfRows = million * 100; //million * 200 ;//1000;//million * 200 ; //200 million 

    long startTime = System.currentTimeMillis(); 

    long counter = 1; 
    //byte[] messageBytes = (counter+"").getBytes(Charset.forName("UTF-8")); 
    //long bufferSize = (counter + "\n").getBytes(Charset.forName("UTF-8")).length * 1000; 
    while(true) 
    {   
     if(!mappedBuffer.hasRemaining()) 
     { 
      startPosMappedBuffer += mappedBuffer.position(); 
      mappedBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, startPosMappedBuffer, bufferSize); 
     } 
     mappedBuffer.put((counter + System.lineSeparator()).getBytes(Charset.forName("UTF-8"))); //+ System.lineSeparator() //putLong(counter); //); 
     //mappedBuffer.rewind(); 

     counter++; 
     if(counter > numberOfRows) 
      break; 
    } 
    fileAccess.close(); 
    long endTime = System.currentTimeMillis(); 
    long actualTimeTaken = endTime - startTime; 
    System.out.println(String.format("No Of Rows %s , Time(sec) %s ", numberOfRows, actualTimeTaken/1000f)) ; 
} 

Des indices sur le problème?

Édition 1: Le problème d'exception est résolu et résolu comme ci-dessous.

Édition 2: Concernant la meilleure option pour la performance.

@EJP: voici le code utilisant DataOutputStream autour de BufferedOutputStream.

static void writeFileDataBuffered() throws IOException{ 
     File file = File.createTempFile("dbf", ".txt", new File("C:\\Output")); 
     DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); 
     long counter = 1; 
     long million = 1000000; 
     long numberOfRows = million * 100; 
     long startTime = System.currentTimeMillis(); 
     while(true){ 
      out.writeBytes(counter + System.lineSeparator()); 
      counter++; 
      if (counter > numberOfRows) 
       break; 
     } 
     out.close(); 
     long endTime = System.currentTimeMillis(); 
     System.out.println("Number of Rows: "+ numberOfRows + ", Time(sec): " + (endTime - startTime)/1000f); 
    } 

.......... Merci

+0

'MappedByteBuffers' ont pratiquement nul effet sur la performance. Vous devriez commencer par un 'DataOutputStream' autour d'un' BufferedOutputStream' et ensuite voir si vous avez vraiment un problème de performance d'E/S. – EJP

+0

@EJP: Merci pour votre commentaire. J'ai essayé tous les deux de dériver l'approche optimale. Mes résultats pour 100 millions de disques sont:
DataOutputStream -> Nombre de lignes: 100000000, Temps (s): 31,707 MappedByteBuffer -> Nombre de lignes: 100000000, Temps (s): 16,576 – Gana

+0

Puis-je savoir la raison vers le bas vote? Est-ce le changement de portée de la question? – Gana

Répondre

0

Après un travail de fond, j'ai découvert la cause racine. Le bufferSize que j'ai déclaré était inférieur à la longueur du contenu que j'écris. Le nombre d'octets requis pour 100 millions d'enregistrements est: 988888898 tandis que bufferSize with (long) (Math.pow (10240, 2)) est: 104857600. bufferSize est court par 884031298 octets. Cela causait le problème comme l'indique l'exception. Le bufferSize peut également être utilisé comme Integer.MAX_VALUE au lieu de calculer la taille du contenu en cours d'écriture.

Bien que cela augmente la taille du fichier, cela n'a aucun impact sur les performances du programme, selon mes résultats d'essai.

.........

Merci