【发布时间】:2014-01-13 01:42:17
【问题描述】:
我确定以前有人问过这个问题,但我找到的答案都不能很好地适用于我现有的代码。我发布这个问题以防万一有办法在不完全重做我目前所做的事情的情况下做到这一点。
这个想法是在将文件和目录从一个驱动器复制到另一个驱动器时显示一个非常基本的进度条。我有一个名为 BasicCopy 的类,旨在将图片、文档、视频和音乐文件夹(Windows 机器上的标准)的内容复制到第二个驱动器上的备份目录中的同名文件夹。这是到目前为止的课程:
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);
}
}
我在前一个类中有一个方法可以测量目录的总大小,所以如果需要,我可以将它传递给这个类。但是,我目前只遍历四个目录,所以我希望我无法以高于 25% 的分辨率递增进度条。我想知道是否有一种方法可以更改它,以便我可以包含一个进度条来监视它,并让它更准确一点?此外,我不确定是否应该在不同的线程中询问,但这种文件复制方法需要很长时间。复制 500MB 的文件需要几个小时,我想知道是否有办法加快速度?不过,那部分不是优先事项。现在我主要对添加进度条感兴趣。干杯!
编辑:
经过一番摆弄后,我意识到我可能可以使用类似的代码(这个确切的代码可能有效,也可能无效——我只是快速记下它,所以我不会忘记它,它仍然未经测试)。这将允许我更新每个复制文件的进度条。
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();
}
}
}
编辑 #2:
我在代码上做了更多的工作,我相信我已经弄清楚了大部分。现在的问题是关于 SwingWorker,我相信我需要它才能在后台运行长期方法。否则 GUI 会变得无响应(Java 文档中有很多关于此的文档)。但是,这就是我卡住的地方。我以前只使用过一次 SwingWorker,主要是复制代码。我想知道如何使用以下代码来实现它,以便实际出现进度条(以及框架的其余部分)。
更新代码:
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);
}
}
【问题讨论】:
-
“我找到的答案都不能很好地适用于我现有的代码” 为什么不呢?
-
它们都需要完全重写,需要不同的方法来循环文件、创建目录等。我按照我的方式设置循环是有原因的,我真的希望我能调整进度条以使用它,因为我的代码运行正常。
-
1)
btnCancel.setBounds(169, 227, 89, 23);您从哪里获得代码示例?底线是那是非常糟糕的代码,不应该这样做。我想知道是什么资源导致人们走上了这条错误的道路。 2) 作为一般建议:不要阻塞 EDT(事件调度线程)——当这种情况发生时,GUI 将“冻结”。而不是调用Thread.sleep(n)实现一个SwingTimer用于重复任务或一个SwingWorker用于长时间运行的任务。有关详细信息,请参阅Concurrency in Swing。 -
“我真的希望我可以调整进度条来使用它”我真的希望圣诞节能有一匹小马。我们并不总是得到我们想要的..
-
哈哈,是的,我明白我可能不明白,我意识到我可能不得不完全重写,但我发布了这个问题,以防万一我有办法做到这一点使用我现有的代码。无论如何,1) 部分布局(例如您在之前的评论中提到的取消按钮代码)是使用 WindowBuilder 创建的。我将按钮放在布局选项卡上我想要的位置,它会自动为我生成代码。 2) 我知道我不应该阻止 EDT,这就是为什么我在最近的编辑中发布了代码并附有评论;我需要应用一个 swingworker 而不是在 EDT 中调用方法
标签: java swing file copy jprogressbar