4

我有下面的代码来复制目录和文件,但不确定在哪里测量进度。有人可以帮助
我在哪里可以测量复制了多少并将其显示在 JProgress 栏中

public static void copy(File src, File dest)
throws IOException{
if(src.isDirectory()){
        if(!dest.exists()){ //checking whether destination directory exisits
           dest.mkdir();
           System.out.println("Directory copied from " 
                        + src + "  to " + dest);
        }

        String files[] = src.list();

        for (String file : files) {

           File srcFile = new File(src, file);
           File destFile = new File(dest, file);

           copyFolder(srcFile,destFile);
        }
  }else{
        InputStream in = new FileInputStream(src);
          OutputStream out = new FileOutputStream(dest); 

          byte[] buffer = new byte[1024];

          int length;

          while ((length = in.read(buffer)) > 0){
           out.write(buffer, 0, length);
          }

          in.close();
          out.close();
          System.out.println("File copied from " + src + " to " + dest);
  }
4

3 回答 3

14

我刚刚为您编写了这个实用程序 :)(大约需要 3 个小时):

在此处输入图像描述

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.DefaultCaret;

public class FileCopierUtility extends JFrame implements ActionListener, PropertyChangeListener
{
    private static final long serialVersionUID = 1L;

    private JTextField txtSource;
    private JTextField txtTarget;
    private JProgressBar progressAll;
    private JProgressBar progressCurrent;
    private JTextArea txtDetails;
    private JButton btnCopy;
    private CopyTask task;

    public FileCopierUtility()
    {
        buildGUI();
    }

    private void buildGUI()
    {
        setTitle("File Copier Utility");
        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);

        addWindowListener(new WindowAdapter()
        {
            @Override
            public void windowClosing(WindowEvent e)
            {
                if(task != null) task.cancel(true);
                dispose();
                System.exit(0);
            }
        });

        JLabel lblSource = new JLabel("Source Path: ");
        JLabel lblTarget = new JLabel("Target Path: ");
        txtSource = new JTextField(50);
        txtTarget = new JTextField(50);
        JLabel lblProgressAll = new JLabel("Overall: ");
        JLabel lblProgressCurrent = new JLabel("Current File: ");
        progressAll = new JProgressBar(0, 100);
        progressAll.setStringPainted(true);
        progressCurrent = new JProgressBar(0, 100);
        progressCurrent.setStringPainted(true);
        txtDetails = new JTextArea(5, 50);
        txtDetails.setEditable(false);
        DefaultCaret caret = (DefaultCaret) txtDetails.getCaret();
        caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
        JScrollPane scrollPane = new JScrollPane(txtDetails, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        btnCopy = new JButton("Copy");
        btnCopy.setFocusPainted(false);
        btnCopy.setEnabled(false);
        btnCopy.addActionListener(this);

        DocumentListener listener = new DocumentListener()
        {
            @Override
            public void removeUpdate(DocumentEvent e)
            {
                boolean bEnabled = txtSource.getText().length() > 0 && txtTarget.getText().length() > 0;
                btnCopy.setEnabled(bEnabled);
            }

            @Override
            public void insertUpdate(DocumentEvent e)
            {
                boolean bEnabled = txtSource.getText().length() > 0 && txtTarget.getText().length() > 0;
                btnCopy.setEnabled(bEnabled);
            }

            @Override
            public void changedUpdate(DocumentEvent e){}
        };

        txtSource.getDocument().addDocumentListener(listener);
        txtTarget.getDocument().addDocumentListener(listener);

        JPanel contentPane = (JPanel) getContentPane();
        contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        JPanel panInputLabels = new JPanel(new BorderLayout(0, 5));
        JPanel panInputFields = new JPanel(new BorderLayout(0, 5));
        JPanel panProgressLabels = new JPanel(new BorderLayout(0, 5));
        JPanel panProgressBars = new JPanel(new BorderLayout(0, 5));

        panInputLabels.add(lblSource, BorderLayout.NORTH);
        panInputLabels.add(lblTarget, BorderLayout.CENTER);
        panInputFields.add(txtSource, BorderLayout.NORTH);
        panInputFields.add(txtTarget, BorderLayout.CENTER);
        panProgressLabels.add(lblProgressAll, BorderLayout.NORTH);
        panProgressLabels.add(lblProgressCurrent, BorderLayout.CENTER);
        panProgressBars.add(progressAll, BorderLayout.NORTH);
        panProgressBars.add(progressCurrent, BorderLayout.CENTER);

        JPanel panInput = new JPanel(new BorderLayout(0, 5));
        panInput.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("Input"), BorderFactory.createEmptyBorder(5, 5, 5, 5)));
        JPanel panProgress = new JPanel(new BorderLayout(0, 5));
        panProgress.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("Progress"), BorderFactory.createEmptyBorder(5, 5, 5, 5)));
        JPanel panDetails = new JPanel(new BorderLayout());
        panDetails.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("Details"), BorderFactory.createEmptyBorder(5, 5, 5, 5)));
        JPanel panControls = new JPanel(new BorderLayout());
        panControls.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));

        panInput.add(panInputLabels, BorderLayout.LINE_START);
        panInput.add(panInputFields, BorderLayout.CENTER);
        panProgress.add(panProgressLabels, BorderLayout.LINE_START);
        panProgress.add(panProgressBars, BorderLayout.CENTER);
        panDetails.add(scrollPane, BorderLayout.CENTER);
        panControls.add(btnCopy, BorderLayout.CENTER);

        JPanel panUpper = new JPanel(new BorderLayout());
        panUpper.add(panInput, BorderLayout.NORTH);
        panUpper.add(panProgress, BorderLayout.SOUTH);

        contentPane.add(panUpper, BorderLayout.NORTH);
        contentPane.add(panDetails, BorderLayout.CENTER);
        contentPane.add(panControls, BorderLayout.SOUTH);

        pack();
        setLocationRelativeTo(null);
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        if("Copy".equals(btnCopy.getText()))
        {
            File source = new File(txtSource.getText());
            File target = new File(txtTarget.getText());

            if(!source.exists())
            {
                JOptionPane.showMessageDialog(this, "The source file/directory does not exist!", "ERROR", JOptionPane.ERROR_MESSAGE);
                return;
            }

            if(!target.exists() && source.isDirectory()) target.mkdirs();
            else
            {
                int option = JOptionPane.showConfirmDialog(this, "The target file/directory already exists, do you want to overwrite it?", "Overwrite the target", JOptionPane.YES_NO_OPTION);
                if(option != JOptionPane.YES_OPTION) return;
            }

            task = this.new CopyTask(source, target);
            task.addPropertyChangeListener(this);
            task.execute();

            btnCopy.setText("Cancel");
        }
        else if("Cancel".equals(btnCopy.getText()))
        {
            task.cancel(true);
            btnCopy.setText("Copy");
        }
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt)
    {
        if("progress".equals(evt.getPropertyName()))
        {
            int progress = (Integer) evt.getNewValue();
            progressAll.setValue(progress);
        }
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {   
            @Override
            public void run()
            {
                new FileCopierUtility().setVisible(true);
            }
        });
    }

    class CopyTask extends SwingWorker<Void, Integer>
    {
        private File source;
        private File target;
        private long totalBytes = 0L;
        private long copiedBytes = 0L;

        public CopyTask(File source, File target)
        {
            this.source = source;
            this.target = target;

            progressAll.setValue(0);
            progressCurrent.setValue(0);
        }

        @Override
        public Void doInBackground() throws Exception
        {
            txtDetails.append("Retrieving some info ... ");
            retrieveTotalBytes(source);
            txtDetails.append("Done!\n");

            copyFiles(source, target);
            return null;
        }

        @Override
        public void process(List<Integer> chunks)
        {
            for(int i : chunks)
            {
                progressCurrent.setValue(i);
            }
        }

        @Override
        public void done()
        {
            setProgress(100);
            btnCopy.setText("Copy");
        }

        private void retrieveTotalBytes(File sourceFile)
        {
            File[] files = sourceFile.listFiles();
            for(File file : files)
            {
                if(file.isDirectory()) retrieveTotalBytes(file);
                else totalBytes += file.length();
            }
        }

        private void copyFiles(File sourceFile, File targetFile) throws IOException
        {
            if(sourceFile.isDirectory())
            {
                if(!targetFile.exists()) targetFile.mkdirs();

                String[] filePaths = sourceFile.list();

                for(String filePath : filePaths)
                {
                    File srcFile = new File(sourceFile, filePath);
                    File destFile = new File(targetFile, filePath);

                    copyFiles(srcFile, destFile);
                }
            }
            else
            {
                txtDetails.append("Copying " + sourceFile.getAbsolutePath() + " ... ");

                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFile));
                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetFile));

                long fileBytes = sourceFile.length();
                long soFar = 0L;

                int theByte;

                while((theByte = bis.read()) != -1)
                {
                    bos.write(theByte);

                    setProgress((int) (copiedBytes++ * 100 / totalBytes));
                    publish((int) (soFar++ * 100 / fileBytes));
                }

                bis.close();
                bos.close();

                publish(100);

                txtDetails.append("Done!\n");
            }
        }
    }
}
于 2012-11-27T01:46:23.780 回答
4

To accomplish this, you have to figure out the number of copy operations in advance. You did not include your copyFolder method, but I assume that you would like to perform a recursive copy. If so, you have to traverse the whole directory tree to figure out how many files you are going to copy. This can get nasty for the user when dealing with large directory structures. (This is why modern operation systems often display an annoying "preparing to copy..." - message before the operation starts and progress is displayed)

于 2012-11-26T23:02:30.050 回答
4

显示文件的进度相当简单......

long expectedBytes = src.length(); // This is the number of bytes we expected to copy..
byte[] buffer = new byte[1024];
int length;
long totalBytesCopied = 0; // This will track the total number of bytes we've copied
while ((length = in.read(buffer)) > 0){
    out.write(buffer, 0, length);
    totalBytesCopied += length;
    int progress = (int)Math.round(((double)totalBytesCopied / (double)expectedBytes) * 100);
    setProgress(progress); // From SwingWorker
}

如果您想提供有关要复制/已开始复制的总字节数的信息,它会变得有点复杂。

你在这里有选择。您可以预先扫描所有文件夹(我会将文件放入某种队列中)并计算要复制的总字节数/文件数。然后开始实际的复制过程。

为此更新进度与之前的示例一样简单,只是您将累积在整个过程中复制的字节总数,而不是单个文件。

或者...

您可以使用生产者/消费者算法。这个想法是启动一个线程/工作者,其唯一职责是扫描文件夹以查找要复制的文件并将它们放入中央/共享队列(这是生产者)。

您将拥有第二个线程/工作者,它将弹出该队列的下一项(阻塞到新文件变得可用)并实际复制该文件。

这里的技巧是让队列维护一个计数器来记录通过它的文件和字节总数,这将允许您调整总作业的正在进行的进度......

于 2012-11-26T23:09:56.900 回答