lina: FileChooser und grosse Datenmengen

moin :)

Ich habe in meiner Applikation einen JFileChooser mit FileFilter (nur Bild-dateien werden angezeigt).
Er funktioniert auch wunderbar. Nur leider ist das Verzeichnis, dass ich als Standardverzeichnis übergebe eines mit sehr sehr vielen Dateien (und es ist abzusehen, dass es noch sehr sehr viel mehr werden). Ich nehme an deswegen schläft der FileChooser fast ein beim Laden... es dauert mitunter bis zu zwei Minuten ehe die Dateien angezeigt werden :( Das ist eindeutig zu langsam und führt zu Akzeptanzproblemen bei den Usern.
Hat jemand Ideen vielleicht wie man das Laden beschleunigen kann?
Vielen Dank :)

liebe Gruesse lina

--
ss:| ls:] fo:| de:] ch:? rl:? br:> js:( ie:% fl:| mo:) \nWer nicht versucht hat schon verloren.
  1. Hi,

    die Frage ist: ist es ein Core-Java-Problem (also lokalisiert im FileChooser, auf welchen Du keinen Einfluss hast) oder ist es vielmehr ein Problem Deines Codes (FileFilter)? Poste doch einmal den code der accept()-Methode.

    Viele Grüße,
    Martin Jung

    1. moin :)

      Poste doch einmal den code der accept()-Methode.

      ok ;)
      public boolean accept(File f){
        if(f.isDirectory()){
          return true;
        }
        else{
          boolean erlaubt=false;
          String name=f.toString();
          name=name.subString(name.indexOf("."));
          for(int i=0; i<=extension.length-1; i++){
            if(name.indexOf(extension[i]!=-1){
              erlaubt=true;
              i=extension.length;
            }
            else erlaubt =false;
          }
          if(erlaubt==true) return true;
          else return false;
        }
      }

      Dies funktioniert ja soweit auch ganz gut. Nur eben viel zu langsam :( In dem Array extension befinden sich alle Endungen die erlaubt sind (also gif, jpg und png)
      Gibt es da Optimierungsmöglichkeiten?

      liebe Gruesse lina

      --
      ss:| ls:] fo:| de:] ch:? rl:? br:> js:( ie:% fl:| mo:)
      Wer nicht versucht hat schon verloren.
      1. public boolean accept(File f){
          if(f.isDirectory()){
            return true;
          }
          else{
            boolean erlaubt=false;
            String name=f.toString();
            name=name.subString(name.indexOf("."));
            for(int i=0; i<=extension.length-1; i++){
              if(name.indexOf(extension[i]!=-1){
                erlaubt=true;
                i=extension.length;
              }
              else erlaubt =false;
            }
            if(erlaubt==true) return true;
            else return false;
          }
        }

        public boolean accept(File f)
        {
          if (f.isDirectory())
          {
            return true;
          }
          else
          {
            String name = f.toString();
            name = name.substring(name.lastIndexOf('.'));

        for (int i = 0; i < extension.length; i++)
            {
              if (name.indexOf(extension[i] != -1)
              {
                return true;
              }
            }

        return false;
          }
        }

        Mit freundlichen Grüßen
           Dimitri Rettig

        --
        Meistens gelangen die Menschen nur durch die Folgen der Unordnung zur Einführung der Ordnung, und Gesetzlosigkeit führt gewöhnlich erst zu Gesetzen.
          -- Friedrich Schiller
        1. Hallo,

          wie in dem oberen Thread schon gesagt wurde, ist es effektiver, wenn du die Dateiendungen mit dem Trennpunkt im Array speicherst. Dann sieht meine Lösung so aus:

          private String[] extension = {".gif", ".jpg", ".png"};

          public boolean accept(File f)
          {
            if (f.isDirectory())
            {
              return true;
            }
            // Wozu soll es eigentlich gut sein, hier true zurück zu geben?

          String name = f.toString();

          for (int i = 0; i < extension.length; i++)
            {
              if (name.endsWith(extension[i])
              {
                return true;
              }
            }
            return false;
          }

          Du kannst dir viele Anweisungen ersparen, wenn du beachtest, dass mit return die jeweilige Methode verlassen wird. Das heißt, dass der nachfolgende Code nicht mehr ausgeführt wird.

          Deine Methode ist eine typische statische Methode. Besser ist es also:

          public static boolean accept(File f, String[] extension)

          Dies solle deine "Haputmethode" sein. Auf diese kannst du dann weitere, ähnliche Methoden aufsetzen. Sinnvoll währen Methoden wie:

          private String[] DEFAULT_EXTENSIONS = {".gif", ".jpg", ".png"};

          public static boolean accept(File f)
          {
            return accept(f, DEFAULT_EXTENSIONS);
          }

          public static boolean accept(String path, String[] extension)
          public static boolean accept(String path)

          Achte auch schön auf Exceptions. Dadurch wird deine Klasse flexibler und zuverlässiger.

          Mit freundlichen Grüßen
             Dimitri Rettig

          --
          Meistens gelangen die Menschen nur durch die Folgen der Unordnung zur Einführung der Ordnung, und Gesetzlosigkeit führt gewöhnlich erst zu Gesetzen.
            -- Friedrich Schiller
          1. moin :)
            Erstmal vielen vielen Dank für all eure Antworten! Leider bin ich erst heute dazu gekommen, das alles zu lesen. Werde es heute gleich mal in die Tat umsetzen und euch später berichten, was und wie es geklappt hat :)
            Vielen Dank nochmal :)
            Ihr seid echt spitze!
            liebe Gruesse lina

            --
            ss:| ls:] fo:| de:] ch:? rl:? br:> js:( ie:% fl:| mo:)
            Wer nicht versucht hat schon verloren.
            1. moin :)
              So: hab das ganze mal in die Tat umgesetzt - und siehe da: die Zeit hat sich auf 7 Sekunden reduziert (bei 240 Dateien im Ordner).
              Ist das eine normale Zeit oder lässt sich da noch was rausholen?
              Auf jeden Fall sieht das schon mal viel viel besser aus so :)
              Zu der Frage warum ich true zurückgebe wenn f ein Ordner ist: In dem Ordner wo die Bilder drin sind, gibt es einen Unterordner "Administration", der auch Bilder enthält und mit speziellen Rechten versehen ist. Dieser muss natürlich auch mit angezeigt werden ;) wenn ich die Abfrage if(f.isDirectory){return true} weglasse wird er nicht angezeigt.

              Vielen Dank für die Hilfe nochmal :)
              liebe Gruesse lina

              --
              ss:| ls:] fo:| de:] ch:? rl:? br:> js:( ie:% fl:| mo:)
              Wer nicht versucht hat schon verloren.
              1. Hallo Lina,

                So: hab das ganze mal in die Tat umgesetzt - und siehe da: die Zeit hat sich auf 7 Sekunden reduziert (bei 240 Dateien im Ordner).
                Ist das eine normale Zeit oder lässt sich da noch was rausholen?

                Das kommt natürlich auch auf den Rechner an, wie schnell das ist. Welche Variante hast Du denn jetzt verwendet?
                Viel rausholen lässt sich aber vermutlich nicht mehr.

                Grüße

                Daniel

                1. moin :)

                  Das kommt natürlich auch auf den Rechner an, wie schnell das ist. Welche Variante hast Du denn jetzt verwendet?
                  Viel rausholen lässt sich aber vermutlich nicht mehr.

                  Naja - die Rechner sind vermutlich nicht die allerschnellsten...
                  Ich habe einen Mix aus einigen Varianten genommen ;)
                  statt .toString() für den Namen habe ich .getName() verwendet,
                  das return habe ich natuerlich für den Abbruch der Methode (und damit auch der Schleife genommen) -> wieso bin ich da eigentlich nicht selber drauf gekommen? *g*
                  Zu guter Letzt habe ich dann noch die Abfrage, ob die Endung auch stimmt .endsWith genommen.

                  Mit den Zeiten die das Laden jetzt braucht bin ich zwar nicht 100% glücklich aber ich werde damit leben können ;) Kollegen die rummeckern gibbet ja immer *g* also was solls.
                  Vielen Dank nochmal :)
                  liebe Gruesse lina

                  --
                  ss:| ls:] fo:| de:] ch:? rl:? br:> js:( ie:% fl:| mo:)
                  Wer nicht versucht hat schon verloren.
      2. Hi,

        public boolean accept(File f){
          if(f.isDirectory()){
            return true;
          }
          else{
            boolean erlaubt=false;
            String name=f.toString();
            name=name.subString(name.indexOf("."));
            for(int i=0; i<=extension.length-1; i++){
              if(name.indexOf(extension[i]!=-1){
                erlaubt=true;
                i=extension.length;
              }
              else erlaubt =false;
            }
            if(erlaubt==true) return true;
            else return false;
          }
        }

        Gibt es da Optimierungsmöglichkeiten?

        Ja.

        1. Die einfachste und daher sinnvollste:
        Speichere in besagtem Verzeichnis einfach nur Image-Dateien, und zwar auschließlich diese, die der FileChooser auch anzeigen darf. Dann müsstest Du höchstens das Verzeichnis auf Gültigkeit prüfen (dessen Pfad/Namen man ja extern konfigurierbar machen kann). accept() könnte dann folgendermaßen aussehen:

        public boolean accept(File f){
           if(f.isDirectory()){
              // Pseudo-Code
              if(DirectoryIsCorrekt()) {
                return true;
              }
           }
           return false;
         }

        Andere Optimierungen im else-Zweig, wenn obiges nicht realisierbar ist:

        2. Extension-Abfrage:
        Speichere die Extensions im Array zusammen mit dem Prefix-Dot (".gif" etc.), dann kannst Du Dir die Generation eines String-Objekts sparen. Desweiteren gibt es noch einige nicht notwendige Statements, die zur Laufzeit aber ausgeführt werden und daher Zeit in Anspruch nehmen. accept() könnte dann folgendermaßen aussehen:

        public boolean accept(File f){
           if(f.isDirectory()){
             return true;
           }
           else{
             String name=f.getPath();   // siehe 3.
             for(int i=0; i<=extension.length-1; i++) {
               if(name.indexOf(extension[i]!=-1){
                  // Achtung: diese if-Abfrage würde auch folgendes durchgehen lassen:
                  // <testdocument.gif.txt>
                  // ganz sicher ist man mit <name.endsWith(extension[i])>
                 return true;   // durch die return-Anweisung 'verlässt'
                                // Du an dieser Stelle die Methode und
                                // implizit die Schleife ;-)

        // weitere Anmerkung
                 // i=extension.length;
                 // was bezweckst Du mit letztem Statement eigentlich?
                 // Das, was Du hier anscheindend möchstest, erreicht man
                 // - wenn notwendig (dies ist hier nicht der Fall!) - verständlicher mit <break;>
               }
             }
             return false;
           }
         }

        3. String name = f.getPath(); // String name=f.toString();
        Im Archiv findest Du einen Thread (genauer: http://forum.de.selfhtml.org/archiv/2003/1/35197/#m192657, indem herausgearbeitet wurde, das die Verwendung von .toString() u.U. langsamer sein kann als die der 'direkten' Get-Methoden. In der Summe kann sich das aber bereits bemerkbar machen (oder eben auch nicht, ich habe das nur der Vollständigkeit halber hier erwähnt).

        Übrigens: ich habe den Code nicht durch Testen geprüft ;-)

        Viele Grüße,
        Martin Jung

      3. Hallo Lina,

        Ich würde das so implementieren:

        HashSet extensions = new HashSet();

        public boolean accept(File f){
          if(f.isDirectory()) {
            return true;
          }
          else {
            int i = f.getName().lastIndexOf('.');
            return i != -1 && extensions.contains(f.getName().substring(i + 1));
          }
        }

        indexOf durchsucht immer den ganzen String von vorne. Das ist bei langen Pfaden und vielen Dateien natürlich langsam.
        Außerdem ist ein HashSet bei vielen Elementen wesentlich schneller als ein Array, wenn man darin ein bestimmtes Element finden will. So lange Du nur wenige zulässige Endungen hast, wirkt sich das aber vermutlich nicht aus.

        Grüße

        Daniel

    2. Hi,

      es gibt hier zwar viele schöne Lösungen der accept()-Methode aber die Original-Methode war nicht so schlecht programmiert dass dadurch 2 Minuten!!! Laufzeit rauskommen können!

      Das Problem hängt eher irgendwo in der Bestückung des JFileChoosers.

      Bei JTable gibt es auch Probleme wenn mehr als 1000 Zeilen reinkommen. Da bricht die Performanz komplett ein.

      Schau mal bei Sun im Forum. Da findest Du bestimmt irgendwas.

      Ciao
      Thomas

      1. Hi,

        es gibt hier zwar viele schöne Lösungen der accept()-Methode aber die Original-Methode war nicht so schlecht programmiert dass dadurch 2 Minuten!!! Laufzeit rauskommen können!

        Im Original-Posting stand nichts Konkretes bzgl. der Anzahl der Dateien (analog zum JTable-mehr-als-1000Zeilen-Beispiel), daher ist die Angabe "..dauert mitunter bis zu zwei Minuten.." sowieso von geringem Informationswert.

        Davon abgesehen lautet die Frage im Posting:
        "Hat jemand Ideen vielleicht wie man das Laden beschleunigen kann?"

        Viele Grüße,
        Martin Jung

        1. Hallo Martin,

          Davon abgesehen lautet die Frage im Posting:
          "Hat jemand Ideen vielleicht wie man das Laden beschleunigen kann?"

          das ist korrekt. Es bringt meiner Erfahrung nach nur überhaupt nichts bei Laufzeiten die in der Minutenecke angesiedelt sind (selbst bei 20000 Dateien) an ein paar kleinen Speicheroperationen  herumzutunen. Die accept war in dem Fall zwar nicht optimal programmiert aber sie war auch keine völlige Killer-Methode die 100 mal so lange gebraucht hätte wie die geposteten Verbesserungen.

          Ciao
          Thomas Grötzner

          --
          Signatur? Was ist das?
      2. Hallo,

        Das Problem hängt eher irgendwo in der Bestückung des JFileChoosers.

        Das kann man nicht so einfach sagen. Bei mir zeigt der JFileChooser den Inhalt von /etc/bin (über 2000 Dateien) sehr schnell an.
        Sollte tatsächlich der JFileChooser zu langsam sein, hilft sowieso nichts.

        Grüße

        Daniel

      3. Hallo,

        Das Problem hängt eher irgendwo in der Bestückung des JFileChoosers.

        Mein JFileChooser braucht zum Laden eines Ordners mit 1000 Dateien keine 2 Minuten. Das Problem könnte im Rechner (Leistung) oder in der JVM sein. Ich würde die neueste JVM von Sun istallieren.

        Mit freundlichen Grüßen
           Dimitri Rettig

        --
        Meistens gelangen die Menschen nur durch die Folgen der Unordnung zur Einführung der Ordnung, und Gesetzlosigkeit führt gewöhnlich erst zu Gesetzen.
          -- Friedrich Schiller
  2. moin :)

    Selber Moin ;o),
    guck mal hier:
    http://www.wir-age.de/home/spatiarc/index.html

    Wenn du dir die Sourcen runterziehst, wirst du auch einen JFile Chooser finden. Leider weiss ich nicht mehr genau, wie ich den FileFilter gebaut habe, aber auch bei grossen Verzeichnissen war der relativ fix (war, glaube ich, irgendein Sun Beispiel, das ich da verwurstet habe).

    HTH
    Ralf Rapude