使用Java复制文件时的进度条
我确信这个问题以前有人问过,但我发现的所有答案都不能很好地与我现有的代码配合使用。我在这里发布这个问题,以防有一种方法可以在不完全重做我到目前为止所做的事情的情况下完成它 其思想是在将文件和目录从一个驱动器复制到另一个驱动器时显示一个非常基本的进度条。我有一个名为BasicCopy的类,用于将图片、文档、视频和音乐文件夹(Windows机器上的标准)的内容复制到第二个驱动器上备份目录中同名的文件夹中。以下是到目前为止的课程:使用Java复制文件时的进度条,java,swing,file,copy,jprogressbar,Java,Swing,File,Copy,Jprogressbar,我确信这个问题以前有人问过,但我发现的所有答案都不能很好地与我现有的代码配合使用。我在这里发布这个问题,以防有一种方法可以在不完全重做我到目前为止所做的事情的情况下完成它 其思想是在将文件和目录从一个驱动器复制到另一个驱动器时显示一个非常基本的进度条。我有一个名为BasicCopy的类,用于将图片、文档、视频和音乐文件夹(Windows机器上的标准)的内容复制到第二个驱动器上备份目录中同名的文件夹中。以下是到目前为止的课程: import java.io.File; import java.io
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);
}
}
导入java.io.File;
导入java.io.IOException;
导入java.text.simpleDataFormat;
导入java.util.Date;
导入org.apache.commons.io.FileUtils;
公共类基本副本{
字符串username=“”;
字符串mainDrive=“”;
字符串backupDrive=“”;
字符串backupDir=“”;
字符串[]目录;
公共基本副本(字符串inDrive、字符串OUTDIVE、字符串用户名){
主驱动=独立驱动;
备份驱动器=输出驱动器;
this.username=用户名;
createBackupDirectory();
复制目录();
close();
}
//创建备份目录
public void createBackupDirectory(){
日期=新日期();
SimpleDataFormat sdf=新的SimpleDataFormat(“MM-dd-yyyy_HMMSS”);
字符串时间戳=sdf.format(日期);
backupDir=backupDrive+“:\ \”+“Backup”+时间戳;
File backupDirectory=新文件(backupDir);
backupDirectory.mkdir();
}
公共无效复制目录(){
//主目录
字符串pics=mainDrive+“:\\Users\\”+username+“\\Pictures”;
字符串docs=mainDrive+“:\\Users\\”+username+“\\Documents”;
字符串vids=mainDrive+“:\\Users\\”+username+“\\Videos”;
字符串musc=mainDrive+“:\\Users\\”+username+“\\Music”;
//备份目录
字符串bkPics=backupDir+“\\Pictures”;
字符串bkDocs=backupDir+“\\Documents”;
字符串bkVids=backupDir+“\\Documents”;
字符串bkMusc=backupDir+“\\Pictures”;
String[]目录={pics,docs,vids,musc};
字符串[]bkDirectories={bkPics,bkDocs,bkVids,bkMusc};
//循环浏览目录并复制文件
对于(int i=0;i
我在上一个类中有一个方法,用于测量目录的总大小,因此如果需要,我可以将其传递给这个类。然而,我目前只循环浏览了四个目录,所以我希望我不能以高于每刻度25%的分辨率增加进度条。我想知道是否有一种方法我可以改变它,以便我可以包括一个进度条来监控它,并让它更准确一点?此外,我不确定这是否应该在不同的线程中询问,但这种文件复制方法需要很长时间。复制500MB的文件需要几个小时,我想知道是否有办法加快速度?但这一部分并不是优先考虑的。现在我主要感兴趣的是添加一个进度条。干杯
编辑:
public interface DirectoryMovementStatusFeedback {
void notifyStatus(double percentMoved, double speedInMB);
}
public class FileMovementStatusUpdater {
private long checkInterval = 2000;
private boolean interrupted = false;
public long getCheckInterval() {
return checkInterval;
}
public void setCheckInterval(long checkInterval) {
this.checkInterval = checkInterval;
}
public void monitor(File directory, long desiredSize, DirectoryMovementStatusFeedback feedback) {
new Thread(new Runnable() {
@Override
public void run() {
try {
double percentageMoved = 0;
double lastCheckedSize = 0;
do {
double currentSize = directory.exists() ? FileUtils.sizeOfDirectory(directory) : 0;
double speed = (currentSize - lastCheckedSize) / (1024 * checkInterval);
lastCheckedSize = currentSize;
percentageMoved = 100 * currentSize / desiredSize;
feedback.notifyStatus(percentageMoved, speed);
Thread.sleep(checkInterval);
} while (percentageMoved < 100 && !interrupted);
} catch (Exception e) {
System.err.println("Directory monitor failed. " + e.getMessage());
}
}
}).start();
}
public void stopMonitoring() {
this.interrupted = true;
}
FileMovementStatusUpdater dirStatus = new FileMovementStatusUpdater();
try {
dirStatus.monitor(destination, FileUtils.sizeOfDirectory(source), (percent, speed) -> {
progressBar.setValue(percent);
speedLabel.setValue(speed+" MB/s");
});
FileUtils.moveDirectory(source, destination);
} catch (Exception e) {
// something
}
dirStatus.stopMonitoring();
在做了一些修改之后,我意识到我可能会使用类似的代码(这个确切的代码可能有效,也可能无效——我只是快速地记下来,这样我就不会忘记它,它仍然没有经过测试)。这将允许我为每个复制的文件更新进度条
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();
}
}
}
for(int i=0;i
编辑#2:
public interface DirectoryMovementStatusFeedback {
void notifyStatus(double percentMoved, double speedInMB);
}
public class FileMovementStatusUpdater {
private long checkInterval = 2000;
private boolean interrupted = false;
public long getCheckInterval() {
return checkInterval;
}
public void setCheckInterval(long checkInterval) {
this.checkInterval = checkInterval;
}
public void monitor(File directory, long desiredSize, DirectoryMovementStatusFeedback feedback) {
new Thread(new Runnable() {
@Override
public void run() {
try {
double percentageMoved = 0;
double lastCheckedSize = 0;
do {
double currentSize = directory.exists() ? FileUtils.sizeOfDirectory(directory) : 0;
double speed = (currentSize - lastCheckedSize) / (1024 * checkInterval);
lastCheckedSize = currentSize;
percentageMoved = 100 * currentSize / desiredSize;
feedback.notifyStatus(percentageMoved, speed);
Thread.sleep(checkInterval);
} while (percentageMoved < 100 && !interrupted);
} catch (Exception e) {
System.err.println("Directory monitor failed. " + e.getMessage());
}
}
}).start();
}
public void stopMonitoring() {
this.interrupted = true;
}
FileMovementStatusUpdater dirStatus = new FileMovementStatusUpdater();
try {
dirStatus.monitor(destination, FileUtils.sizeOfDirectory(source), (percent, speed) -> {
progressBar.setValue(percent);
speedLabel.setValue(speed+" MB/s");
});
FileUtils.moveDirectory(source, destination);
} catch (Exception e) {
// something
}
dirStatus.stopMonitoring();
我在代码方面做了更多的工作,我相信我已经解决了大部分问题。现在的问题是关于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);
}
}
导入java.awt.Toolkit;
导入java.awt.event.WindowEvent;
导入java.io.File;
导入java.io.IOException;
导入java.text.simpleDataFormat;
导入java.util.Date;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.border.EmptyBorder;
导入javax.swing.JTextArea;
导入javax.swing.JButton;
导入javax.swing.JProgressBar;
导入javax.swing.JLabel;
导入org.apache.commons.io.FileUtils;
@抑制警告(“串行”)
公共类BasicCopy扩展了JFrame{
私有JPanel内容窗格;
私人JTextArea txtCopiedDirs;
私人JButton btnCancel;
私人JProgressBar progressBar;
私人JLabel lblCopying;
专用字符串主驱动器;
专用字符串备份驱动器;
私有字符串用户名;
私有字符串backupDir;
long totalSize=0;//目录/文件的总大小
long currentSize=0;//文件的当前大小最多为百分之一
int currentPercent=0;//当前进度,单位为%
长百分之一;//totalSize/100
公共基本副本(){
}
公共基本副本(字符串inDrive、字符串OUTDIVE、字符串用户名、长空格){
主驱动=独立驱动;
FileMovementStatusUpdater dirStatus = new FileMovementStatusUpdater();
try {
dirStatus.monitor(destination, FileUtils.sizeOfDirectory(source), (percent, speed) -> {
progressBar.setValue(percent);
speedLabel.setValue(speed+" MB/s");
});
FileUtils.moveDirectory(source, destination);
} catch (Exception e) {
// something
}
dirStatus.stopMonitoring();