Need to have JProgress bar to measure progress when copying directories and files

后端 未结 3 619
臣服心动
臣服心动 2020-12-18 10:11

I have the below code to copy directories and files but not sure where to measure the progress. Can someone help
as to where can I measure how much has been copied and s

相关标签:
3条回答
  • 2020-12-18 10:29

    Showing the progress for a file is rather simple...

    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
    }
    

    If you want to provide information about the total number of bytes to be copied/has begin copied, it becomes a little more complicated.

    You have choices here. You either pre-scan all the folders (I'd be placing the files into some kind of queue) and calculate the total bytes/number of files to be copied. Then start the actual copy process.

    Updating the progress for this is as simple as the example before, except you'd be accumulating the total number of bytes you've copied over the whole process instead of a single file.

    OR...

    You could use a producer/consumer algorithm. The idea would be to start a thread/worker whose sole responsibility was to scan the folders for the files to be copied and place them into a central/shared queue (this is the producer).

    You would have a second thread/worker that would pop the next item of this queue (blocking into a new file became available) and would actually copy the file.

    The trick here is for the queue to maintain a counter to the total number of files and bytes that has passed through it, this will allow you to adjust the ongoing progress of total job...

    0 讨论(0)
  • 2020-12-18 10:30

    I have just written this utility for you :) (It takes me about 3 hours):

    enter image description here

    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");
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-18 10:35

    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)

    0 讨论(0)
提交回复
热议问题