java - Java 中的批处理文件进程被终止 : xcopy does not close

标签 java batch-file xcopy kill-process

这看起来应该很容易解决,但我不太熟悉如何使用批处理文件来自己解决这个问题。我有一个 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;
}

我遇到的问题是这样的:当我运行程序时,文件复制得很好,除非我按前台窗口上的停止按钮。当我这样做时,它告诉我备份已取消(正如预期的那样),但它留下了三个额外的进程正在运行,这些进程在任务管理器中可见: enter image description here

enter image description here

enter image description here

我的猜测是第一个——“扩展复制实用程序”是罪魁祸首。由于它没有关闭,因此其他两个 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/

相关文章:

java - 如何将 currentTimeMillis 转换为可读的日期格式?

android - 从批处理文件中打开 Android 签名向导

batch-file - 将所有子目录中的所有.txt文件合并到一个txt文件中

java - 第一次绘制时图形上下文未对齐

java - Java 套接字中的 HTTP

c# - C# 控制台批处理应用程序中的最佳计时器方法

batch-file - 批处理文件 For 循环遍历具有排除项的文件扩展名列表

batch-file - 自动复制文件而不覆盖,而是创建编号文件

sql-server-2008 - 如何部署SQL Server Compact Edition 4.0?

java - Apache Pulsar - 从不同线程确认