0

似乎长时间运行的 tree walker 任务应该在这样的类中定义:

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

并开始这样的地方:

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

长时间运行的任务不仅由对类中的方法的一次调用发起,而且完全由其执行。所以肯定对它的调用必须在.walkFileTree()FilesdoInBackGround()

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

请注意,walkTreeFile() 内部会为遇到的每个文件调用四个方法。程序员编写的循环是不可行的。所以这是我的问题。如何使用publish()将文件信息作为字符串发送到process我需要覆盖的方法?我见过的例子有publish()inside doInBackground(),但是在一个循环中,这在这里是不可能的。

我最关心的四种方法之一是visitFile(),它walkFileTree()需要能够找到,我怀疑这是放置的地方publish()

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

我可以将 walkFileTree() 调用的所有 4 个方法放在内部类 insidedoInBackground()中,但这似乎是一厢情愿的想法。

PS我不能用get();这就是重点(据我所知)——获得结果的延迟太长(可能要处理数千个文件才能找到十几个文件)才能等到 doInBackground() 结束。

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

编辑#3,原始发布时间后 50 分钟

  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.
    }   

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

(编辑#2,发布后 40 分钟)

这是我的处理方法。println 没有执行。

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

此外,包含的类语句doInBackground()已更改:

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

该类Walking嵌套在doInBackground().

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

(编辑,发布后 20 分钟)

这编译但什么也没做:

  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()

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

...另一个怪异的编辑...我现在的班级定义...

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 ......

4

3 回答 3

1

因为您的TreeWalkerextendsSwingWorker和 implements FileVisitor,您可以publish从任何回调方法中调用,例如...

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

现在,根据您的需要,您需要使用您需要Path的任何方法将元素转换为...String

更新了工作示例

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;
        }
    }

}

注意,这没有 GUI,而是通过等待get返回来等待工作人员完成,这仅作为示例

于 2013-11-19T00:16:34.000 回答
0

由于@Madprogrammer 没有使用 GUI 并且 DID 使用 get() [等待 doInBackground() 执行完成],我添加了一个 GUI,修改了他的 publish(),并包含了对 done() 的调用,就像结冰一样在蛋糕上。我自己的树行者还不能用,但 Mad 给我指路了。以下是新的 Mad-with-GUI 版本的亮点。

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);
      }
于 2013-11-19T23:02:18.800 回答
0

不是我放弃 SwingWorker,只是确定自己对线程不了解,决定做点什么。过去 2 天,我在一个更简单的项目上取得了成功,这使我将相同的策略应用于我的(各种)Treewalker(项目),现在:(1)在将输出附加到 textarea 时不要使屏幕闪烁(2)按下按钮即可优雅地结束。

它所要做的只是为“后台”任务使用一个单独的线程(不是 SwingWorker)FileVisitor,它:(a)让 GUI 保持“负责”,从而能够无缝地接受输出,并为用户提供一个按钮来按下以中止和 (b) 使代码看起来合理且易于理解。

所以@Mad,再次感谢您的帮助。(自 11 月 19 日以来,我一直没有单独在这方面工作!我很沮丧,我只是离开了它,成功地做了其他事情,并鼓起勇气回来再试一次)。

PS 我发现Ivar Horton 的 Java 入门(7) 文本非常宝贵。我见过的最好的线程。

FWIW 这是我的备份程序的概要:

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;
  }                                      
}
于 2013-12-08T02:46:41.767 回答