Кажется, это должно быть довольно легко решить, но я недостаточно знаком с использованием пакетных файлов, чтобы решить это самостоятельно. У меня есть метод Java, который создает построитель процессов и запускает пакетный файл в процессе. Пакетный файл использует команду xcopy для копирования одного каталога в другой. Пока пакетный файл выполняется в фоновом режиме, окно Java, содержащее JTextArea, отображает выходные данные процесса (копируемые каталоги). В окне также есть кнопка остановки, которая вызывает следующий код:
stopped = true;
backgroundTask.cancel(true);
backgroundTask.done();
Готовый метод выглядит так:
protected void done() {
statusLabel.setText((this.getState()).toString() + " " + status);
stopButton.setEnabled(false);
bar.setIndeterminate(false);
if(stopped == false){
JOptionPane.showMessageDialog(null, "Backup Complete.");
closeWindow();
}
else if (stopped == true){
JOptionPane.showMessageDialog(null, "Backup Cancelled.");
closeWindow();
}
}
Теперь, чтобы запустить пакетный файл в фоновом режиме, я использую следующий код (изначально предложенный мне trashgod):
protected Integer doInBackground() throws IOException {
try {
ProcessBuilder pb = new ProcessBuilder(commands);
pb.redirectErrorStream(true);
Process p = pb.start();
String s;
BufferedReader stdout = new BufferedReader(
new InputStreamReader(p.getInputStream()));
while ((s = stdout.readLine()) != null && !isCancelled()) {
publish(s);
}
if (!isCancelled()) {
status = p.waitFor();
}
p.getInputStream().close();
p.getOutputStream().close();
p.getErrorStream().close();
p.destroy();
closeWindow();
} catch (IOException | InterruptedException ex) {
ex.printStackTrace(System.err);
}
return status;
}
Проблема, с которой я сталкиваюсь, заключается в следующем: когда я запускаю программу, файлы копируются просто отлично, если я не нажму кнопку остановки в окне на переднем плане. Когда я это делаю, мне сообщается, что резервное копирование было отменено (как и предполагалось), но остаются запущенными три дополнительных процесса, которые видны в диспетчере задач:
Я предполагаю, что виновником является первая из них — «утилита расширенного копирования». Поскольку он не закрывается, два других процесса cmd остаются запущенными. Однако это довольно необоснованное предположение.
Когда я запускаю программу, а затем останавливаю ее, проводник Windows становится очень нестабильным, иногда зависает, а иногда и вовсе падает. Навигация по папкам, особенно по копируемым каталогам, происходит очень медленно, и кажется, что каталоги продолжают копироваться даже после того, как процесс (предположительно) остановлен. Я считаю, что это потому, что эти строки никогда не достигаются:
p.getInputStream().close();
p.getOutputStream().close();
p.getErrorStream().close();
p.destroy();
поэтому процесс никогда не убивается. Я все еще работаю над способом полного уничтожения процессов при нажатии кнопки остановки, но если у кого есть мысли, я с удовольствием их выслушаю!
ИЗМЕНИТЬ
Я решил опубликовать весь класс, поскольку предоставление только определенных методов, вероятно, не дает достаточно информации. Вот весь класс:
package diana;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import javax.swing.*;
@SuppressWarnings("serial")
public class Progress extends JFrame {
public String[] commands;
private final JLabel statusLabel = new JLabel("Status: ", JLabel.CENTER);
private final JTextArea textArea = new JTextArea(20, 20);
private JButton stopButton = new JButton("Stop");
private JProgressBar bar = new JProgressBar();
private BackgroundTask backgroundTask;
private ProcessBuilder pb;
private Process p;
public boolean stopped = false;
public void setCommands(String[] cmds) {
commands = cmds;
}
private final ActionListener buttonActions = new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
JButton source = (JButton) ae.getSource();
if (source == stopButton) {
stopped = true;
backgroundTask.cancel(true);
backgroundTask.done();
} else {
backgroundTask = new BackgroundTask(commands);
}
}
};
private void displayGUI(String[] cmds) {
commands = cmds;
JFrame frame = new JFrame("Backup Progress");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
panel.setLayout(new BorderLayout(5, 5));
JScrollPane sp = new JScrollPane();
sp.setBorder(BorderFactory.createTitledBorder("Output: "));
sp.setViewportView(textArea);
textArea.setText(null);
stopButton.setEnabled(true);
backgroundTask = new BackgroundTask(commands);
backgroundTask.execute();
bar.setIndeterminate(true);
stopButton.addActionListener(buttonActions);
JPanel buttonPanel = new JPanel();
buttonPanel.add(stopButton);
buttonPanel.add(bar);
panel.add(statusLabel, BorderLayout.PAGE_START);
panel.add(sp, BorderLayout.CENTER);
panel.add(buttonPanel, BorderLayout.PAGE_END);
frame.setContentPane(panel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
/* Close current window */
public void closeWindow() throws IOException {
p.getInputStream().close();
p.getOutputStream().close();
p.getErrorStream().close();
p.destroy();
WindowEvent close = new WindowEvent(this, WindowEvent.WINDOW_CLOSING);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(close);
System.exit(0);
}
private class BackgroundTask extends SwingWorker<Integer, String> {
private int status;
public String[] commands;
public BackgroundTask(String[] cmds) {
commands = cmds;
statusLabel.setText((this.getState()).toString());
}
@Override
protected Integer doInBackground() throws IOException {
try {
pb = new ProcessBuilder(commands);
pb.redirectErrorStream(true);
p = pb.start();
String s;
BufferedReader stdout = new BufferedReader(
new InputStreamReader(p.getInputStream()));
while ((s = stdout.readLine()) != null && !isCancelled()) {
publish(s);
}
if (!isCancelled()) {
status = p.waitFor();
}
closeWindow();
} catch (IOException | InterruptedException ex) {
ex.printStackTrace(System.err);
}
return status;
}
@Override
protected void process(List<String> messages) {
statusLabel.setText((this.getState()).toString());
for (String message : messages) {
textArea.append(message + "\n");
}
}
@Override
protected void done() {
statusLabel.setText((this.getState()).toString() + " " + status);
stopButton.setEnabled(false);
bar.setIndeterminate(false);
if (stopped == false) {
JOptionPane.showMessageDialog(null, "Backup Complete.");
try {
closeWindow();
} catch (IOException e) {
e.printStackTrace();
}
} else if (stopped == true) {
JOptionPane.showMessageDialog(null, "Backup Cancelled.");
try {
closeWindow();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void run(String[] cmds) {
commands = cmds;
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new Progress().displayGUI(commands);
}
});
}
}
Еще раз, я не могу взять на себя ответственность за этот код, так как он в основном предоставлен членам SO Trashgod. Кроме того, прошу извинить за любые оставленные там утверждения для отладки, которые я, возможно, забыл удалить.