![](/img/trans.png)
[英]Files.walkFileTree leaking directory descriptors with custom FileVisitor
[英]Swingworker with FileVisitor class and walkFileTree(), which iterates internally over a “set” of files in a directory tree; where to publish()?
似乎长时间运行的tree walker任务应在如下类中定义:
public class TreeWalker extends SwingWorker<Void,String> implements FileVisitor<Path>
并开始这样的地方:
TreeWalker walker = (new TreeWalker());
walker.execute();
在长时间运行的任务不仅是由发起的,而是由一个单一的通话完全进行了 walkFileTree()
在方法Files
类。 因此,肯定是必须在doInBackGround()
进行调用。
protected Void doInBackground() throws Exception {
Files.walkFileTree(SearchyGUI.p , this);
return null;
}
请注意, walkTreeFile()
内部为遇到的每个文件调用四个方法。 程序员编写的循环是不可行的。 所以这是我的问题。 如何使用publish()
将文件信息作为字符串发送到需要覆盖的process
方法? 我见过的示例在doInBackground()
publish()
内部有publish()
,但在循环内部,在这里是不可能的。
我最关心的四种方法之一是visitFile()
,该walkFileTree()
需要能够找到,但我怀疑这是将publish()
放在哪里的方法:
public FileVisitResult visitFile(Path f, BasicFileAttributes a) throws IOException {
if (...we want this file...)
publish(f.toString());
return CONTINUE;
}
我可以把所有的4个方法是walkFileTree()调用一个内部类中doInBackground()
但是这似乎是一厢情愿。
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()
=============================
...另一个freakin的编辑...我当前的班级防御...
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
... zzzzzzzzzzzzzzzzzzzzz ...........
因为TreeWalker
扩展了SwingWorker
并实现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
返回仅仅意味着作为示例
由于@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);
}
不是我放弃了SwingWorker,而是只是确定自己对线程不了解,因此决定对此做些事情。 在过去两天里,我通过一个简单得多的项目获得了成功,这促使我将相同的策略应用于我的(各种)Treewalker(项目),该策略现在:(1)在将输出追加到文本区域时不使屏幕闪烁,以及(2)结束并立即按下按钮。
它所要做的就是为“后台” FileVisitor
任务使用一个单独的线程(而不是SwingWorker),该线程:(a)让GUI保持“负责”状态,因此能够无缝地接受输出并为用户提供一个按钮按下以中止操作;(b)使代码看起来理智,易于遵循。
因此,@ Mad,再次感谢AGAIN的帮助。 (自11月19日以来,我就不再单独从事此工作!我感到非常沮丧,我只是离开了它,成功完成了其他工作,然后又有勇气再试一次)。
PS我发现Ivar Horton的Beginning 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;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.