9
votes

Façon plus rapide de lire le fichier

Je travaille sur un programme qui compte environ 400 fichiers d'entrée et environ 40 fichiers de sortie. C'est simple: il lit chaque fichier d'entrée et génère un nouveau fichier avec mais beaucoup plus grand (basé sur un algorithme).

J'utilise la méthode de lecture () à partir de bufferedreader: p>

BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
        new FileOutputStream("fileName"), encoding));

writer.write(textToWrite);


7 commentaires

Avez-vous essayé d'analyser différentes tailles de tampons?


Est le goulot d'étranglement dans le fichier IO ou dans l'algorithme que vous utilisez pour combiner les données?


@Cc Si ma réponse ne vous donne aucune amélioration de la vitesse, vous pouvez toujours essayer d'épiler l'opération de lecture. Faire des lectures simultanées pourraient augmenter la performance (mais pourrait également se dégrader)


Quelle est la taille des fichiers? Quelle est la vitesse du disque dur?


Si vous lisez / écriture sur un lecteur local (un lecteur de réseau serait beaucoup plus lent) de prendre 12 minutes (par exemple 6 lit) Les fichiers devraient être d'environ 10 Go sont une taille de lecture et des écrivies ou environ 25 Mo. et 250 Mo écrit en moyenne. Est-ce que ça sonne bien? Si votre disque est votre disque est votre limite. Sinon, alors E / S n'est pas votre cou de bouteille.


Vérifiez cette question ... Stackoverflow.com/Questtions/5800361/...


Avez-vous envisagé de faire de la multithreading? Si vous avez Multi Core, vous pouvez accélérer le processus, mais le disque dur sera toujours un cou de bouteille.


3 Réponses :


20
votes

Vous devriez être capable de trouver une réponse ici:

http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_Quickly << / p>

Pour les meilleures performances de lecture Java, il y a quatre choses à retenir:

  • minimiser les opérations d'E / S en lisant un tableau à la fois, pas un octet à la fois. Un tableau de 8 kmbyte est une bonne taille.

  • minimiser les appels de méthode en obtenant des données un tableau à la fois, pas un octet à la fois. Utilisez l'indexation du tableau pour obtenir à des octets dans la matrice.

  • Réduisez les serrures de synchronisation de fil si vous n'avez pas besoin de sécurité de fil. Établissez moins d'appels de méthodes à une classe de fil de sécurité ou utilisez une classe sans fil non-fil comme FileChannel et mappébytebuffer.

  • Minimiser la copie de données entre les tableaux JVM / OS, les tampons internes et les matrices d'applications. Utilisez FILECHANNEL avec mappage de mémoire, ou un byTEBUFFER DIRECT ou EPANCÉE DIRECT ou enveloppé.


1 commentaires

Les réponses de liaison seule ne sont pas idéales. Pourriez-vous au moins résumer les conclusions de l'article? (Merci!)



5
votes

Comme vous ne donnez pas trop de détails, je pourrais vous signaler pour essayer d'utiliser des fichiers mapé de mémoire:

String charsetName = "UTF-16"; // choose the apropriate charset.
CharBuffer cb =  Charsert.forName(charsetName).decode(mbb);
String text = cb.toString();


6 commentaires

L'OP veut lire le fichier comme texte. Vous voudrez peut-être inclure comment vous lisez mappé mappébytebuffer avec le codage par défaut (ou un spécifique comme UTF-8)


Alors qu'il lit le fichier mappé comme des octets, pas de mater le débit. Il devra spécifier le codage lors de la construction de la chaîne: String S = nouvelle chaîne (MBB.Array (), Charset.utf-8), prenant soin de si le tableau est chargé, si ce n'est pas le cas, il sera nécessaire de lire en utilisant Ascharbuffer () et doivent également connaître la taille et le contenu de la matrice.


Ah, mais le diable est dans les détails. ;) Par exemple, vous ne pouvez pas décoder une chaîne dans laquelle un octet d'un caractère a été lu mais un autre n'a pas. ;) Je ne crois pas que vous puissiez appeler mbb.array () sur une mappebytebuffer


En effet sur le MBB.Array, j'ai raté cet important détail. Il aura besoin d'utiliser la méthode Charset.Decode, je mettrai à jour ma réponse en l'utilisant.


+1: Son pas simple à avoir raison, l'ajout d'un exemple est utile.


Sachez qu'une fois qu'un fichier a été mappé, un certain nombre d'opérations sur ce fichier échouera jusqu'à ce que le mappage soit libéré (par exemple, supprimer, tronquer à une taille inférieure à la zone mappée), mais il existe actuellement (jusqu'à Java10?) Pas de moyen de Relâchez la cartographie sauf en attente de la GC: Bugs.java.com/bugdatabase/view_bug. faire? bug_id = 4724038



2
votes

Les tampons d'octets mappés sont le moyen le plus rapide:

 FileInputStream f = new FileInputStream( name );
FileChannel ch = f.getChannel( );
MappedByteBuffer mb = ch.map( ch.MapMode.READ_ONLY,
    0L, ch.size( ) );
byte[] barray = new byte[SIZE];
long checkSum = 0L;
int nGet;
while( mb.hasRemaining( ) )
{
    nGet = Math.min( mb.remaining( ), SIZE );
    mb.get( barray, 0, nGet );
    for ( int i=0; i<nGet; i++ )
    checkSum += barray[i];
}


1 commentaires

Ne fonctionne pas pour les gros fichiers, qui ont une taille plus grande que INTEGER.MAX_VALUE