Swingworker с классом FileVisitor и walkFileTree(), который выполняет внутреннюю итерацию по "набору" файлов в дереве каталогов; где опубликовать ()?
Кажется, что долго выполняемая задача обходчика деревьев должна быть определена в классе следующим образом:
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
метод мне нужно переопределить? Примеры, которые я видел, имеют publish()
внутри doInBackground()
, но внутри цикла, что здесь невозможно.
Один из четырех методов, которые меня больше всего волнуют, 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 минут после публикации)
Вот мой метод обработки. Печать не выполнена.
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...........
3 ответа
Потому что ваш 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;
}
}
}
Nb, у этого нет GUI с этим, но вместо этого ждет рабочего, чтобы закончить, ожидая get
возвращаться только в качестве примера
Так как @Madprogrammer не использовал GUI, а DID использовал get() [который ЖДЕТ, пока не завершится выполнение doInBackground()], я добавил GUI, изменил его publish() и включил вызов done (), просто как обледенение на торте. Мой собственный ходок по дереву еще не работает, но Безумный показал мне путь. Вот основные моменты новой версии 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, я просто решил, что не знаю, как сидеть на корточках, и решил что-то с этим сделать. Мой успех в последние 2 дня в гораздо более простом проекте привел меня к применению той же стратегии к моим (различным) Treewalker (проектам), которые теперь: (1) не заставляют мигать экран при добавлении вывода в текстовую область и (2) закончить изящно и немедленно нажатием кнопки.
Все, что для этого потребовалось - использовать отдельный поток (не SwingWorker) для "фона" FileVisitor
задача, которая: (а) позволяет графическому интерфейсу оставаться "ответственным" и, таким образом, иметь возможность беспрепятственно принимать вывод, а также предоставляет пользователю кнопку для отмены и (б) делает код более разумным и легким для отслеживания.
Так что @Mad, СНОВА спасибо за помощь. (Я не работаю только над этим с 19 ноября! Я так расстроился, что просто ушел, занялся другими делами и получил смелость вернуться и попробовать снова).
PS Я нашел текст "Начало 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;
}
}