Есть консольное приложение, которое считает количество файлов в 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.Не забудьте что ваш список для собранных данных должен быть потокобезопасным.
Оборудование для ресторана: новинки профессиональной кухонной техники
Частный дом престарелых в Киеве: комфорт, забота и профессиональный уход
Пишу чат бот для Facebook и столкнулся с проблемой при получении payload с нажатой кнопки юзером
Написал метод, который строить пирамиду из символов "^"Саму пирамиду рисует правильно, только вот есть лишний пробел и переход на новую строку,...