IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Entrée/Sortie Java Discussion :

[Copie de Fichier] Quelle méthode est la plus rapide ?


Sujet :

Entrée/Sortie Java

  1. #1
    Membre régulier
    Inscrit en
    Avril 2006
    Messages
    238
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 238
    Points : 90
    Points
    90
    Par défaut [Copie de Fichier] Quelle méthode est la plus rapide ?
    Bonjour,
    j'ai besoin de faire un copier coller de fichier en java.
    Pour cela, j'ai trouvé deux exemples de code qui répondent à mon besoin.

    Voici le premier :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    import java.io.*;
     
    public class JCopy{
      public static void main(String args[]){
        try {
          JCopy j = new JCopy();
          j.copyFile(new File(args[0]),new File(args[1]));
          }
        catch (Exception e) {
          e.printStackTrace();
          }
        }
     
      public void copyFile(File in, File out) throws Exception {
        FileInputStream fis  = new FileInputStream(in);
        FileOutputStream fos = new FileOutputStream(out);
        byte[] buf = new byte[1024];
        int i = 0;
        while((i=fis.read(buf))!=-1) {
          fos.write(buf, 0, i);
          }
        fis.close();
        fos.close();
        }
      }
    Et le deuxième :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    import java.nio.channels.*;
    import java.io.*;
     
    public class JCopy2{
      public static void main(String args[]){
        try {
          JCopy2 j = new JCopy2();
          j.copyFile(new File(args[0]),new File(args[1]));
        }
        catch (Exception e) {
          e.printStackTrace();
        }
     }
     
      public void copyFile(File in, File out) throws Exception {
         FileChannel sourceChannel = new
              FileInputStream(in).getChannel();
         FileChannel destinationChannel = new
              FileOutputStream(out).getChannel();
         sourceChannel.transferTo(0, sourceChannel.size(), destinationChannel);
         // or
         //  destinationChannel.transferFrom(sourceChannel, 0, sourceChannel.size());
         sourceChannel.close();
         destinationChannel.close();
         }
      }
    Ma question est : comment déterminer le code le plus performant en ce qui concerne la vitesse ? Peut-on chronometrer le temps pour comparer les 2 bouts de code ?

    Merci à vous
    (@_@)

  2. #2
    Membre chevronné
    Profil pro
    Fabrication GED
    Inscrit en
    Octobre 2005
    Messages
    1 405
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Fabrication GED

    Informations forums :
    Inscription : Octobre 2005
    Messages : 1 405
    Points : 1 958
    Points
    1 958
    Par défaut
    Pour chronométrer, tu peux le faire avec : System.currentTimeMillis(), tu en met un au début, un à la fin du traitement et la différence des deux te donnera le nombre de millisecondes écoulée.

  3. #3
    Membre chevronné
    Avatar de afrikha
    Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    1 600
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2005
    Messages : 1 600
    Points : 2 208
    Points
    2 208
    Par défaut
    Le deuxième code est nettement plus rapide que le premier. Le package java.nio a justement été créer pour accroitre la performance.

    Tu peux vérifier cela en faisant la différence entre la date de début et de fin dans les deux cas. Pour obtenir le temps courant en millisecondes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    System.currentTimeMillis();
    P.S: un article est en préparation sur java.io, il sera disponible prochainement.


    Mes publications
    Lisez
    Les régles du forum
    Pensez au bouton

  4. #4
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,


    En effet dans la documentation de transferTo() on peut lire :
    This method is potentially much more efficient than a simple loop that reads from this channel and writes to the target channel. Many operating systems can transfer bytes directly from the filesystem cache to the target channel without actually copying them.

    Sinon je te conseille fortement d'utiliser des bloc try/finally pour bien fermer tes fichiers même en cas d'exception :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
        public void copyFile(File in, File out) throws IOException {
            FileChannel sourceChannel = new FileInputStream(in).getChannel();
            try {
                FileChannel destinationChannel = new FileOutputStream(out).getChannel();
                try {
                    sourceChannel.transferTo(0, sourceChannel.size(), destinationChannel);
                } finally { destinationChannel.close(); }
            } finally { sourceChannel.close(); }
        }
    a++

  5. #5
    Membre régulier
    Inscrit en
    Avril 2006
    Messages
    238
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 238
    Points : 90
    Points
    90
    Par défaut
    J'ai déjà essayé en utilisant le code suivant, mais le problème est que 2 fois sur 3 le programme me signale que le traitement dure moins de 0 millisecondes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    public class Chrono {
        Calendar m_start = new GregorianCalendar();
     
        Calendar m_stop = new GregorianCalendar();
     
        public Chrono() {
        }
     
        // Lance le chronomètre
        public void start() {
            m_start.setTime(new Date());
        }
     
        // Arrète le chronomètre
        public void stop() {
            m_stop.setTime(new Date());
        }
     
        // Retourne le nombre de millisecondes séparant l'appel des méthode start()
        // et stop()
        public long getMilliSec() {
            return (m_stop.getTimeInMillis() - m_start.getTimeInMillis());
        }
     
        // Affiche le nombre de millisecondes séparant l'appel des méthode start()
        // et stop() sur la sortie standard
        public void printMilliSec() {
            if (getMilliSec() <= 0) {
                System.out.println("Vous n'avez pas arrété le chronomètre");
            } else {
                System.out.println("Temps d'exécution : " + getMilliSec() + " ms");
            }
        }
    }
    (@_@)

  6. #6
    Membre chevronné
    Avatar de afrikha
    Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    1 600
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2005
    Messages : 1 600
    Points : 2 208
    Points
    2 208
    Par défaut
    c'est normal, la précision n'est pas vraiment de l'ordre de la milliseconde, ça depend des os...la recopie est trop rapide pour se voir.Essaye avec des fichiers pus conséquents (de l'ordre de quelques Mo ), tu verras la différence...

    [EDIT] tu n'as pas besoin de passer par la classe Calendar
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    long start=System.currenttimeMillis();
    //copie du fichier
    long durée=System.currentTimeMillis()-start;
    [/EDIT]


    Mes publications
    Lisez
    Les régles du forum
    Pensez au bouton

  7. #7
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par n@n¤u
    J'ai déjà essayé en utilisant le code suivant, mais le problème est que 2 fois sur 3 le programme me signale que le traitement dure moins de 0 millisecondes.
    C'est normal car si la valeur retourné est bien en milliseconde, la précision peut varier selon le système...

    Ainsi sous Windows la précision est de l'ordre de 16ms environ... Donc si la méthode dure moins de 16ms il y a de forte chance que tu obtiennes 0 ou 16ms...

    Pour obtenir des résultats utiles, il faut soit que ta méthode dure suffisamment longtemps (+ de 500ms, voire 1s), soit que tu appelles plusieurs fois la méthode dans une boucle afin d'obtenir un temps global plus long...

    Enfin si tu es sous Java 5.0 tu peux utiliser System.nanoTime() qui peut avoir une meilleure précision...

    a++

  8. #8
    Membre régulier
    Inscrit en
    Avril 2006
    Messages
    238
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 238
    Points : 90
    Points
    90
    Par défaut
    Citation Envoyé par adiGuba
    Salut,


    En effet dans la documentation de transferTo() on peut lire :



    Sinon je te conseille fortement d'utiliser des bloc try/finally pour bien fermer tes fichiers même en cas d'exception :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
        public void copyFile(File in, File out) throws IOException {
            FileChannel sourceChannel = new FileInputStream(in).getChannel();
            try {
                FileChannel destinationChannel = new FileOutputStream(out).getChannel();
                try {
                    sourceChannel.transferTo(0, sourceChannel.size(), destinationChannel);
                } finally { destinationChannel.close(); }
            } finally { sourceChannel.close(); }
        }
    a++
    Je ne comprends pas une chose : pourquoi ne pas faire un seul try/finally qui ferme les deux fichiers en même temps ?
    (@_@)

  9. #9
    Membre chevronné
    Homme Profil pro
    Dév. Java & C#
    Inscrit en
    Octobre 2002
    Messages
    1 413
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Dév. Java & C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2002
    Messages : 1 413
    Points : 1 993
    Points
    1 993
    Par défaut
    Bonjour,

    Pas de besoin des classes Date et Calendar. Voici un version plus "légère".
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
    public class Chrono {
        long m_start = 0L;
        long m_stop = 0L;
     
        public Chrono() {
        }
     
        // Lance le chronomètre
        public void start() {
            m_start = System.currentTimeMillis();
        }
     
        // Arrète le chronomètre
        public void stop() {
            m_stop = System.currentTimeMillis();
        }
     
        // Retourne le nombre de millisecondes séparant l'appel des méthode start()
        // et stop()
        public long getMilliSec() {
            return (m_stop - m_start);
        }
     
        // Affiche le nombre de millisecondes séparant l'appel des méthode start()
        // et stop() sur la sortie standard
        public void printMilliSec() {
            if (getMilliSec() <= 0) {
                System.out.println("Vous n'avez pas arrété le chronomètre");
            } else {
                System.out.println("Temps d'exécution : " + getMilliSec() + " ms");
            }
        }
    }
    Si tu travailles avec la version 5, tu peux utiliser la méthode nanoTime au lieu de currentTimeMillis.

    Attention: l'exactitude milli ou nano seconde n'est pas garantie.

    Sous Windows avec la méthode currentTimeMillis, tu as une exactitude d'environ 15ms.
    Bien le bonjour chez vous
    Jowo

  10. #10
    Membre régulier
    Inscrit en
    Avril 2006
    Messages
    238
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 238
    Points : 90
    Points
    90
    Par défaut
    J'ai fait les modifs dans le code du chrono et j'ai maintenant le temps en nano secondes. Mais j'ai un problème la deuxième méthode (celle qui est sensée être plus rapide) met beaucoup plus de temps que la 1ère.
    Je ne comprends plus ?!

    J'ai modifié la deuxième méthode :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    public void copyFile2() {
     
            // Create channel on the source
            FileChannel srcChannel = null;
            FileChannel dstChannel = null;
     
            try {
                srcChannel = new FileInputStream("chemin_1").getChannel();
     
                // Create channel on the destination
                dstChannel = new FileOutputStream("chemin_2").getChannel();
     
                // Copy file contents from source to destination
                dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
     
                // Close the channels
     
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                try {
                    dstChannel.close();
                    srcChannel.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    Je ne comprends toujours pas je dois faire 2 try imbriqués avec deux finally (comme me l'avait conseillé adiGuba)
    Why ???
    (@_@)

  11. #11
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par n@n¤u
    Mais j'ai un problème la deuxième méthode (celle qui est sensée être plus rapide) met beaucoup plus de temps que la 1ère.
    C'est à dire ? qu'est-ce que tu veux dire par "beaucoup plus de temps" ??

    Citation Envoyé par n@n¤u
    Je ne comprends toujours pas je dois faire 2 try imbriqués avec deux finally (comme me l'avait conseillé adiGuba)
    Why ???
    Parce que dans ton code, si tu as une exception lors de l'ouverture d'un des fichier, tu obtiendras par la suite un NullPointerException car il n'aura pas été initialisé...

    Et puis cela permet de bien séparé les deux et de retrouver facilement l'ouverture et la fermeture du fichier...

    Enfin si tu veux traiter les exceptions il vaut mieux le faire un niveau au dessus (comme ca tu ne traites les exception qu'une seule fois) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        public void copyFile(File in, File out) {
            try {
                FileChannel sourceChannel = new FileInputStream(in).getChannel();
                try {
                    FileChannel destinationChannel = new FileOutputStream(out).getChannel();
                    try {
                        sourceChannel.transferTo(0, sourceChannel.size(), destinationChannel);
                    } finally { destinationChannel.close(); }
                } finally { sourceChannel.close(); }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    a++

  12. #12
    Membre régulier
    Inscrit en
    Avril 2006
    Messages
    238
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 238
    Points : 90
    Points
    90
    Par défaut
    Ok d'ac adiGuba, je fais comme tu me le conseille.
    Le temps d'exécution est en général le suivant :

    Temps d'exécution 1ère méthode : 4060572 ns
    Temps d'exécution 2ème méthode : 10065525 ns

    Pourquoi le deuxième est moins performant que le premier, alors que ça devrait être l'inverse. Je fais mes manips avec un fichier de 161Ko.
    (@_@)

  13. #13
    Membre émérite
    Avatar de mavina
    Homme Profil pro
    Développeur Java
    Inscrit en
    Octobre 2004
    Messages
    1 812
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Chine

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2004
    Messages : 1 812
    Points : 2 411
    Points
    2 411
    Par défaut
    Salut,

    Passage furtif pour remarquer que, il me semble, on a déja eu un sujet comme ça, et qu'il était dit que System.getCurrentTimeMillis() n'était pas fiable sous windows... Par contre je me souviens plus trop ce qu'il fallait utiliser comme fonction, c'était dans Quartz il me semble

    mavina, qui fait mine de rien
    Développeur Java / Flex à Shanghai, Chine
    mes publications
    Mon dernier tutoriel : Messages Quit IRC : explications

    La rubrique IRC recrute des redacteurs : contactez moi

    Ce flim n'est pas un flim sur le cyclimse. Merci de votre compréhension.[/SIZE]

  14. #14
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,


    J'optiens des résultats similaires aux tiens... et en fait cela dépend de la taille du fichier...

    Pour de petit fichier (j'ai testé avec un de 300 Ko), la première méthode est plus rapide, mais c'est de l'ordre de 5-7 milliseconde (comme pour toi).

    Pour de fichier plus gros (j'ai testé avec un de 29 Mo), c'est la seconde avec FileChannel qui est plus rapide, avec une différence de l'ordre de 700 millisecondes...


    Donc pour de petit fichier il semble plus rapide de passer par un buffer (et ainsi de charger le fichier en mémoire), alors que pour de gros fichier il vaut mieux passer par FileChannel et le cache du système de fichier...

    J'obtiens de résultat très proche pour des fichier d'environ 1.5 Mo...

    a++

  15. #15
    Membre régulier
    Inscrit en
    Avril 2006
    Messages
    238
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 238
    Points : 90
    Points
    90
    Par défaut
    Merci pour tout.
    Mais aurais-tu plus d'info concernant le post de mavina ? (à propos de Quartz)
    (@_@)

  16. #16
    Membre chevronné
    Avatar de afrikha
    Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    1 600
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2005
    Messages : 1 600
    Points : 2 208
    Points
    2 208
    Par défaut
    Citation Envoyé par n@n¤u
    Merci pour tout.
    Mais aurais-tu plus d'info concernant le post de mavina ? (à propos de Quartz)
    Tutorial sur Quartz


    Mes publications
    Lisez
    Les régles du forum
    Pensez au bouton

  17. #17
    Membre régulier
    Inscrit en
    Avril 2006
    Messages
    238
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 238
    Points : 90
    Points
    90
    Par défaut
    Thanks to everybody !
    (@_@)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Quelle solution est la plus rapide?
    Par tiwicom dans le forum Requêtes et SQL.
    Réponses: 1
    Dernier message: 03/10/2011, 17h54
  2. quelle méthode est la meilleure parmi ces 2 là?
    Par lezebulon dans le forum SDL
    Réponses: 8
    Dernier message: 29/10/2010, 15h22
  3. Réponses: 0
    Dernier message: 08/09/2009, 18h34
  4. regex quelle librairie est la plus rapide
    Par ouiouioui dans le forum Débuter
    Réponses: 11
    Dernier message: 28/01/2009, 15h23
  5. Transfert de fichiers - Quelle méthode ?
    Par Kloun dans le forum Installation, Déploiement et Sécurité
    Réponses: 4
    Dernier message: 06/03/2006, 20h07

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo