Есть консольное приложение, которое считает количество файлов в n-м количестве папок одновременно. Необходимо по нажатию ESC, остановить все потоки и вывести результаты, которые уже посчитало.
Допустим, из 10000 файлов, насчитало 4000, к моменту нажатия на кнопку. И вывести эти 4000. Есть рабочая программа, но ума не приложу, каким образом по нажатию ESC в консоли остановить это все. В интернете нашел такой способ:
public class FileCounter extends Thread implements KeyListener {
private File file;
private String filePath;
private int countOfFiles;
boolean flag;
public FileCounter(String file, String name) {
this.filePath = file;
this.file = new File(file);
setName(name);
}
public int countFiles(File file) {
int count = 0;
flag = false;
try {
File[] folderEntries = file.listFiles();
for (File entry : folderEntries) {
if (entry.isDirectory()) {
count += countFiles(entry);
synchronized (this) {
while (flag) {
System.in.read();
wait();
return count;
}
}
continue;
} else {
count++;
synchronized (this) {
while (flag) {
wait();
return count;
}
}
}
}
}catch (InterruptedException e){
System.out.println(e.getMessage());
}
catch (IOException e){
System.out.println(e.getMessage());
}
return count;
}
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
public int getCountOfFiles() {
return countOfFiles;
}
public String getFilePath() {
return filePath;
}
@Override
public void run() {
this.countOfFiles = countFiles(this.file);
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ESCAPE){
flag = true;
}
}
@Override
public void keyReleased(KeyEvent e) {
}
}
Но у меня он не работает. Скорее всего потому, что в main прописан join на все потоки, что бы если не нажималось esc, вывести конечный результат.
public static void main(String[] args) throws FileNotFoundException {
String target = "E:\\Test\\Test.txt";
String result = "E:\\Test\\result.txt";
List<String> parsedTarget = pathParser(target);
List<Result> results = new ArrayList<>();
FileCounter[] threads = new FileCounter[parsedTarget.size()];
for (int i = 0; i < threads.length; i++) {
threads[i] = new FileCounter(parsedTarget.get(i), String.format("Thread %d", i));
}
startThreads(threads);
try {
for (FileCounter thread : threads) {
thread.join();
if (!thread.isAlive()) {
results.add(new Result(((int) thread.getId())-10, thread.getFilePath(), thread.getCountOfFiles()));
} else if (stop) {
results.add(new Result(((int) thread.getId()), parsedTarget.get(((int) thread.getId())), thread.getCountOfFiles()));
}
}
}catch (InterruptedException e ){
System.out.println(e.getMessage());
}
String res;
for (Result result1 : results){
res = result1.getNum() + " " + result1.getCount() + " " + result1.getPath() + ";";
System.out.println(res);
writeCSV(result,res);
}
}
В циклах обхода по файловой системе нужно проверять флаг Thread.isInterrupted() и если флаг окажется true то выходить из цикла. Изменить этот флаг вы можете при помощи Thread.interrupted() для этого достаточно иметь ссылку на поток в месте где вы вызываете эту остановку. Только учитывайте что такие методы как sleep() и wait() пробуждаются и вызывают InterruptedException.
Более подробно можно прочитать здесь.
Итог:
1.Делайте список с потоками которые собирают файлы так чтобы ссылка на этот список была под рукой в том месте где вы будете реализовывать остановку Назовем его threadsFinder.
2.Добавляете в класс потоков проверку на isInterrupted() в цикле который собирает файлы.
while(!Thread.currentThread().isInterrupted() && естьЧтоСобирать) {
...Ваша логика работы с файлами...
}
3.В случае отказа пользователя от дальнейшего сбора файлов вызываете у всех потоков interrupted():
for(Thread t : threadsFinder) {
t.interrupted();
}
Что приведет к тому что потоки собиратели выйдут из цикла.
4.Не забудьте что ваш список для собранных данных должен быть потокобезопасным.
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости