这看起来应该很容易解决,但我不太熟悉如何使用批处理文件来自己解决这个问题。我有一个 Java 方法,可以创建进程生成器并在进程中运行批处理文件。批处理文件使用 xcopy 命令将一个目录复制到另一个目录。当批处理文件在后台运行时,包含 JTextArea 的 Java 窗口将显示该进程的输出(正在复制的目录)。该窗口还有一个停止按钮,它调用以下代码:
stopped = true;
backgroundTask.cancel(true);
backgroundTask.done();
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();
所以该进程永远不会被终止。我仍在研究一种在按下停止按钮时完全终止进程的方法,但如果有人有想法,我很乐意听到他们!
编辑
我选择发布整个类(class),因为仅提供某些方法可能无法提供足够的信息。这是整个类(class):
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 成员rashgod 提供的。另外,请原谅我可能忘记删除的任何用于调试的语句。
最佳答案
我的想法之一是期望能够阻止整个过程是不合理的。您正在启动一个 shell 并给它一个命令,然后停止原始程序 - 它应该做什么来停止复制?如果您是使用命令 shell 的用户,您可以输入 control-C,但我不知道是否有可用于 Java 的等效编程,可以完成相同的操作。
关于java - Java 中的批处理文件进程被终止 : xcopy does not close,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20722835/