Swingworker with FileVisitor class and walkFileTree(), which iterates internally over a “set” of files in a directory tree; where to publish()?

£可爱£侵袭症+ 提交于 2019-12-04 05:33:46

问题


It seems like the long-running tree walker task should be defined in a class like so:

  public class TreeWalker extends SwingWorker<Void,String> implements FileVisitor<Path>

And begun somewhere like so:

TreeWalker walker = (new TreeWalker());
           walker.execute();

The long-running task is not only initiated by but completely carried out by a single call to walkFileTree(), a method in the Files class. So surely the call to it has to be in doInBackGround().

  protected Void doInBackground() throws Exception {
    Files.walkFileTree(SearchyGUI.p , this);
    return null;
  }

Note that walkTreeFile() internally calls four methods for each file encountered. A programmer-written loop isn't feasible. So there's my problem. How do I use publish() to send file information as a string to the process method I need to override? Examples I've seen have publish() inside doInBackground(), but inside a loop, which is not possible here.

The one of the four methods that I care most about is visitFile(), which walkFileTree() needs to be able to find and I suspect this is where to put publish():

  public FileVisitResult visitFile(Path f, BasicFileAttributes a) throws IOException {
    if (...we want this file...) 
        publish(f.toString());
    return CONTINUE;
  }

I could put all 4 methods that walkFileTree() calls in an inner class inside doInBackground(), but that seems like wishful thinking.

P.S. I can't use get(); that's the whole point (as I understand it)--too much delay in getting results (may process thousands of files to find a dozen) to wait until doInBackground() ends.

==========================================

EDIT #3, 50 minutes after original post time

  public static void doIt(){
      try {
        System.out.println("It begins..."); // This does happen.
        TreeWalker walker = new TreeWalker();
        walker.execute(); 
        SearchyGUI.info.setVisible(true); // Form is displayed, stays blank.
      }      
      catch (Exception e) { System.out.println("Uh-oh"); } // This does NOT happen.
    }   

==========================================

(EDIT #2, 40 minutes after post)

Here's my process method. The println didn't execute.

protected void process(String s) {
    System.out.println("in process()...");
    report(s); // my method to append text area with another line of file info
}

Also, the class statement that contains doInBackground() has changed:

public class TreeWalker extends SwingWorker<Void, String> implements Runnable{

The Walking class is nested within doInBackground().

==========================================

(EDIT, 20 minutes after post)

This compiled but did nothing:

  protected Void doInBackground() throws Exception 
  {
    class Walking implements FileVisitor<Path>
    {  
      @Override
      public FileVisitResult visitFile(Path f, BasicFileAttributes a) throws IOException 
      {
        String modifyDate    = a.lastModifiedTime().toString().substring(0,10);
        String fpathname = f.toString();// + "\\" + f.getFileName().toString());
        if (...we want this one...) 
            publish(f.getFileName());
        return disposition;
      }
... other methods excluded
    } // end inner class    

    System.out.println("walking??");                                 // We get here ...
    Files.walkFileTree(SearchyGUI.p , (FileVisitor<? super Path>) this);
    System.out.println("Finished walking??");                        // ... but not here.
    return null;
  } // end of doInBackground()

=============================

... another freakin' edit ... my current class defs...

public class GUI extends JFrame implements ActionListener, MouseListener, KeyListener

public class TreeWalker extends SwingWorker<Void, String> implements Runnable{

protected Void doInBackground() throws Exception {
  class Walking implements FileVisitor<Path>{ // CLASS INSIDE doInBackground

... zzzzzzzzzzzzzzzzzzz ...........


回答1:


Because your TreeWalker extends both SwingWorker and implements FileVisitor, you could be able to call publish from within any of the call back methods, for example...

public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
    publish(dir.toString());
    return FileVisitResult.CONTINUE;
}

Now, based on your needs, you would need to convert the Path element to a String using what ever method you need...

Updated with working example

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.swing.SwingWorker;

public class TreeWalkerExample {

    public static void main(String[] args) {
        new TreeWalkerExample();
    }

    public TreeWalkerExample() {
        TreeWalker tw = new TreeWalker();
        tw.execute();
        try {
            tw.get();
        } catch (InterruptedException | ExecutionException ex) {
            ex.printStackTrace();
        }
    }

    public class TreeWalker extends SwingWorker<Void, Path> implements FileVisitor<Path> {

        @Override
        protected void process(List<Path> chunks) {
            for (Path p : chunks) {
                System.out.println(p);
            }
        }

        @Override
        protected Void doInBackground() throws Exception {
            Path p = Paths.get(System.getProperty("user.home"));
            System.out.println(p);
            Files.walkFileTree(p, this);
            return null;
        }

        @Override
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
            FileVisitResult fvr = FileVisitResult.CONTINUE;
            if (dir.getFileName().toString().startsWith(".")) {
                fvr = FileVisitResult.SKIP_SUBTREE;
            }
            return fvr;
        }

        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
            publish(file);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
            return FileVisitResult.TERMINATE;
        }

        @Override
        public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
            return FileVisitResult.CONTINUE;
        }
    }

}

Nb, this doesn't have a GUI with it, but instead waits for the worker to complete by waiting for get to return is only meant as an example




回答2:


Since @Madprogrammer didn't use a GUI and DID use get() [which WAITS until execution of doInBackground() finishes], I added a GUI, modified his publish(), and included a call to done(), just as icing on the cake. My own tree walker doesn't work yet, but Mad's shown me the way. Here are the highlights of the new Mad-with-GUI version.

public class TreeWalkerExample {

  static GUI gui;

  public static void main(String args[]) 
  {...invokelater...
     public void run() { 
       gui = new GUI(); 
       gui.setVisible(true); }
   }

      public TreeWalkerExample() { 
        (new TreeWalker()).execute();  
      }

      public class TreeWalker extends SwingWorker<Void,Path> implements FileVisitor<Path> {

          protected Void doInBackground() throws Exception {
              Path p = Paths.get("C:\\","Users","\\Dave","\\Documents","\\Java");
              gui.appendOutput(p.toString());
              Files.walkFileTree(p, this);
              return null;
          }

          public FileVisitResult visitFile(Path file, BasicFileAttributes a) throws IOException{
              publish(file);
              return FileVisitResult.CONTINUE;
          }

          protected void process(List<Path> chunks) {
              for (Path p : chunks) 
                gui.appendOutput(p.getFileName().toString());
          }

          protected void done(){
              gui.appendOutput("\nDone");
          }
    }
    ===================================================================================================
    public class GUI extends javax.swing.JFrame {

      JTextArea output;

      private void btnWalkMouseClicked(java.awt.event.MouseEvent evt) {                                     
        new TreeWalkerExample();
      }                                    

      public void appendOutput(String s){
        output.append("\n" + s);
      }



回答3:


It's not that I gave up on SwingWorker, I just determined that I didn't know squat about threads and decided to do something about it. My success the past 2 days with a much simpler project led me to apply that same strategy to my (various) Treewalker (projects), which now: (1) do not make the screen flash when appending output to a textarea and (2) end gracefully and immediately with a buttonpress.

All it took was using a separate thread (not a SwingWorker) for the "background" FileVisitor task, which: (a) let GUI stay "in charge" and thus be able to accept output seamlessly as well as provide a button for the user to press to abort and (b) makes the code look sane and easy to follow.

So @Mad, thanks AGAIN for the help. (I haven't been working solely on this since Nov. 19! I got so frustrated I just left it, did other stuff successfully, and got the nerve to come back and try again).

P.S. I found the text Ivar Horton's Beginning Java (7) invaluable. Best I've seen about threads.

FWIW here's an outline of my backup program:

public class Copy extends Thread{

  public static FileVisitResult disposition = FileVisitResult.CONTINUE;
  static Thread           t ;
  static FilesCopied      output ;   
...
  public static TreeWalker      fv;
...

  public void run() {    
...
    fv             = new TreeWalker();  
    try {
      Files.walkFileTree(UserIO.inputPath,fv);
    }
    catch ...
  }

  public /* inner */ class TreeWalker implements FileVisitor<Path> {
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
      maybeCopy(file);
      return disposition;
    }
    public FileVisitResult preVisitDirectory(Path d, BasicFileAttributes a) throws IOException {
      maybeMakeDir(d,fromRootDepth);
      return disposition;     
    }
... 
  } // end TreeWalker

...
  public static void main(String[] args) throws IOException {
    EventQueue.invokeLater(new Runnable()  
      public void run() { gui = new UserIO(); gui.setVisible(true); 
    }});  
    EventQueue.invokeLater(new Runnable() {
      public void run() {
        output = new FilesCopied();
      }});
    t = new Copy();
  }
} // end class Copy
======================
public class UserIO extends JFrame {
...
  public void btnBackupMouseClicked(MouseEvent evt) throws IOException { 
...
      Copy.t.start();
  }

  public void btnStopMouseClicked(MouseEvent evt) throws IOException { 
    Copy.disposition = FileVisitResult.TERMINATE;
  }                                      
}


来源:https://stackoverflow.com/questions/20060366/swingworker-with-filevisitor-class-and-walkfiletree-which-iterates-internally

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!