I'm sure this question has been asked before, but none of the answers I found will work very well with my existing code. I'm posting this question in case there's a way to do it without completely redoing what I have so far.
The idea is to display a very basic progress bar while copying files and directories from one drive to another. I have a class called BasicCopy that is designed to copy the contents of the Pictures, Documents, videos, and Music folders (standard on Windows machines) to folders of the same names within a backup directory on a second drive. Here is the class so far:
import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import org.apache.commons.io.FileUtils; public class BasicCopy { String username = ""; String mainDrive = ""; String backupDrive = ""; String backupDir = ""; String[] directories; public BasicCopy(String inDrive, String outDrive, String username){ mainDrive = inDrive; backupDrive = outDrive; this.username = username; createBackupDirectory(); copyDirectories(); close(); } //Create backup directory public void createBackupDirectory(){ Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yyyy_HMMSS"); String timestamp = sdf.format(date); backupDir = backupDrive + ":\\" + "Backup " + timestamp; File backupDirectory = new File(backupDir); backupDirectory.mkdir(); } public void copyDirectories(){ //Main directories String pics = mainDrive + ":\\Users\\" + username + "\\Pictures"; String docs = mainDrive + ":\\Users\\" + username + "\\Documents"; String vids = mainDrive + ":\\Users\\" + username + "\\Videos"; String musc = mainDrive + ":\\Users\\" + username + "\\Music"; //Backup directories String bkPics = backupDir + "\\Pictures"; String bkDocs = backupDir + "\\Documents"; String bkVids = backupDir + "\\Documents"; String bkMusc = backupDir + "\\Pictures"; String[] directories = {pics, docs, vids, musc}; String[] bkDirectories = {bkPics, bkDocs, bkVids, bkMusc}; //Loop through directories and copy files for (int i = 0; i < directories.length; i++){ File src = new File(directories[i]); File dest = new File(bkDirectories[i]); try{ FileUtils.copyDirectory(src, dest); } catch (IOException e){ e.printStackTrace(); } } } /* Close current process */ public void close(){ System.exit(0); } }
I have a method in a previous class that measures the total size of the directories, so I could pass that in to this class if necessary. However, I currently loop through only the four directories, so I expect I wouldn't be able to increment a progress bar with any higher resolution than 25% per tick. I am wondering if there's a way I might change it so that I can include a progress bar to monitor it, and have it be a little more accurate? Furthermore, I'm not sure if this should be asked in a different thread or not, but this method of file copying takes a very long time. It takes hours to copy 500MB worth of files, and I was wondering if there might be a way to speed it up? That part isn't a priority though. Right now I'm mainly interested in adding in a progress bar. Cheers!
EDIT:
After some fiddling I realized I could probably use code similar to this (This exact code may or may not work--I just jotted it down quickly so I wouldn't forget it, it is still untested). This would allow me to update the progress bar for each file copied.
for (int i = 0; i < directories.length; i++){ File dir = new File(directories[i]); File dest = new File(bkDirectories[i]); for(File file: dir.listFiles()){ try{ FileUtils.copyDirectory(file, dest); //update progress bar here } catch (IOException e){ e.printStackTrace(); } } }
EDIT #2:
I have worked a bit more on the code and I believe I've figured most of it out. The question now is about a SwingWorker, which I believe I'll need in order to run the long-term methods in the background. Otherwise the GUI becomes unresponsive (lots of documentation on this in the Java docs). However, this is where I get stuck. I've only used a SwingWorker once before, and that was mainly with copied code. I am wondering how I could implement that using the following code so that the progress bar (and the rest of the frame) actually appears.
Updated code:
import java.awt.Toolkit; import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.border.EmptyBorder; import javax.swing.JTextArea; import javax.swing.JButton; import javax.swing.JProgressBar; import javax.swing.JLabel; import org.apache.commons.io.FileUtils; @SuppressWarnings("serial") public class BasicCopy extends JFrame { private JPanel contentPane; private JTextArea txtCopiedDirs; private JButton btnCancel; private JProgressBar progressBar; private JLabel lblCopying; private String mainDrive; private String backupDrive; private String username; private String backupDir; long totalSize = 0; //total size of directories/files long currentSize = 0; //current size of files counting up to ONE_PERCENT int currentPercent = 0; //current progress in % long ONE_PERCENT; //totalSize / 100 public BasicCopy() { } public BasicCopy(String inDrive, String outDrive, String username, long space){ mainDrive = inDrive; backupDrive = outDrive; this.username = username; totalSize = space; ONE_PERCENT = totalSize/100; createGUI(); /* Should not have these here! * Pretty sure I need a SwingWorker */ createBackupDirectory(); copyDirectories(); } public void createGUI(){ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setTitle("Backup Progress"); setBounds(100, 100, 450, 300); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); contentPane.setLayout(null); txtCopiedDirs = new JTextArea(); txtCopiedDirs.setBounds(10, 56, 414, 125); contentPane.add(txtCopiedDirs); btnCancel = new JButton("Cancel"); btnCancel.setBounds(169, 227, 89, 23); contentPane.add(btnCancel); progressBar = new JProgressBar(0, 100); progressBar.setBounds(10, 192, 414, 24); progressBar.setValue(0); contentPane.add(progressBar); lblCopying = new JLabel("Now backing up your files...."); lblCopying.setBounds(10, 11, 157, 34); contentPane.add(lblCopying); setVisible(true); } //Create backup directory public void createBackupDirectory(){ Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yyyy_HMMSS"); String timestamp = sdf.format(date); backupDir = backupDrive + ":\\" + "Backup " + timestamp; File backupDirectory = new File(backupDir); backupDirectory.mkdir(); } public void copyDirectories(){ //Main directories String pics = mainDrive + ":\\Users\\" + username + "\\Pictures"; String docs = mainDrive + ":\\Users\\" + username + "\\Documents"; String vids = mainDrive + ":\\Users\\" + username + "\\Videos"; String musc = mainDrive + ":\\Users\\" + username + "\\Music"; //Backup directories String bkPics = backupDir + "\\Pictures"; String bkDocs = backupDir + "\\Documents"; String bkVids = backupDir + "\\Documents"; String bkMusc = backupDir + "\\Pictures"; String[] directories = {pics, docs, vids, musc}; String[] bkDirectories = {bkPics, bkDocs, bkVids, bkMusc}; //Loop through directories and copy files for (int i = 0; i < directories.length; i++){ File dir = new File(directories[i]); File dest = new File(bkDirectories[i]); for(File file: dir.listFiles()){ try{ FileUtils.copyDirectory(file, dest); if(getDirSize(file) >= ONE_PERCENT){ currentPercent++; progressBar.setValue(currentPercent); currentSize = 0; } else { currentSize = currentSize + getDirSize(file); if(currentSize >= ONE_PERCENT){ currentPercent++; progressBar.setValue(currentPercent); currentSize = 0; } } } catch (IOException e){ e.printStackTrace(); } } } } public static Long getDirSize(File directory) { long size = 0L; if (directory.listFiles() != null){ for (File file : directory.listFiles()) { size += file.isDirectory() ? getDirSize(file) : file.length(); } } return size; } /* Close current window */ public void closeWindow() { WindowEvent close = new WindowEvent(this, WindowEvent.WINDOW_CLOSING); Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(close); System.exit(0); } }