增量备份文件工具

来源:互联网 发布:win10桌面时钟软件 编辑:程序博客网 时间:2024/06/09 21:48

之前用python写过类似的工具,见本人的另一篇文章(http://blog.csdn.net/dbsync/article/details/6154957)现在把这个工具用java重写了一遍,功能是相同的,使用哪一个,由你自己决定。

该工具我已经打包成JAR包供大家下载,下载地址:http://download.csdn.net/detail/dbsync/5281476

自己有很多资料需要备份到别的地方。问题是之前也做过备份,但是随着资料的不断更新和增加,就会出现原来做的备份跟现在要备份的资料既有重复的,又有新 的,或者是虽然文件名相同,但是内容已经更新了的文件。如果再次备份的话,就需要重新把最新的资料拷贝一遍到目标存储中。如果资料不是很多还好,一旦资料 很多且体积庞大,如此没有差别的拷贝就要花费很多冤枉时间进行覆盖目标存储中相同的资料。能不能只备份新的和已更新的资料,而不拷贝相同的资料呢?这就是 这个脚本的用处,该脚本能够实现增量备份资料功能。



由于是用JAVA写成,因此需要JAVA环境才能运行


现在把源代码附上:

===============================分割线==================================

package BackupFiles;






import java.io.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;




public class BackupFiles {


/**
* @param args
* 本程序用于增量备份文件 */


//存储配置文件内容中源端和目标端目录对应关系
private Map<String,String> dir = new HashMap<String,String>();

private int total = 0;//记录总共备份了多少文件
private long total_size = 0;//记录备份过的文件总共有多大
private int fail = 0;//记录备份失败的文件总数
private int will = 0;//记录应该备份的文件总数

private ArrayList<String> haveBlankFileName = new ArrayList<String>();//存储文件名或路径名中有空格的文件拷贝命令,只适用于linux系统

public static void main(String[] args) throws Exception
{

BackupFiles bf = new BackupFiles();
String s = bf.getDirs();

int mark = 0;
if (s.length() != 0)
{
System.out.println("Waring!在配置文件 backupfiles.conf 中存在非法的配置项:");
System.out.println(s);
System.out.print("是否继续?(Y/N):");
Scanner scan = new Scanner(System.in);
String s2 = scan.nextLine();
if (!s2.toLowerCase().trim().equals("y"))
{
mark = 1;
}
}


if (mark == 1)
{
System.exit(1);
}


//检查源端目录是否都存在
StringBuffer sb = new StringBuffer();
for (Map.Entry<String, String> map : bf.dir.entrySet())
{
int tmp = bf.checkDir(map.getKey());
if (tmp == 0)
{
sb.append(map.getKey() + "\n");
}
}

if (sb.length() > 0)
{
System.out.println("Error!在源端目录中,以下目录并不存在:");
System.out.println(sb.toString());
System.exit(1);
}
//检查完毕



//开始备份文件
Date dt1 = new Date();
long tmp1 = dt1.getTime ();
SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss:SS");

for (Map.Entry<String, String> map : bf.dir.entrySet())
{
ArrayList<String> tmp = bf.getSrcFiles(map.getKey());
for (String s2 : tmp)
{
File file3 = new File(s2);
String s7 = map.getKey ();
if (File.separator.equals ( "\\" ))
{
s7 = map.getKey ().replace ( "\\" , "\\\\" );
}
String[] s3 = s2.split ( s7 );
//String[] s3 = s2.split(map.getKey());//以配置文件中的源端路径名分割文件路径名
String s4 = map.getValue();//得到配置文件中对应的目标端路径名
//System.out.println ("s3.len = " + s3.length + ",s3[0] = " + s3[0]);
//System.out.println ("s2 = " + s2 + ",map.getKey = " + map.getKey ());
File file4 = new File(s4 + s3[1]);
if (file4.isFile())//如果目标端文件存在
{
long src_file = file3.lastModified();
long targ_file = file4.lastModified();
if (src_file > targ_file)//如果源端文件比目标端文件的更新时间新
{
bf.will++;

String s5 = ".bak";
String s6 = s4 + s3[1] + s5;

//查找一个不存在的文件名,用于重命名目标端文件
while (true)
{
File file5 = new File(s6);
if (file5.isFile())
{
s6 = s6 + s5;
}else
{
break;
}
}
//查找完毕

File file5 = new File(s6);
file4.renameTo(file5);//重命名目标端现有文件

int mark2 = bf.CopyFile(s2, s4 + s3[1]);//把源端的文件拷贝到目标端

if (mark2 == 0)//如果拷贝成功
{
file5.delete();//删除备份的文件

Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss:SS");
String dt = sdf.format(date);
String msg = dt + "--" + s2 + "\n";
bf.logs(msg);


}else//如果拷贝不成功
{
file5.renameTo(file4);//把备份的文件恢复成原样
}
}
}else//如果目标端文件不存在
{
bf.will++;

File file = new File(s4 + s3[1]);
String s5 = file.getParent();
File file2 = new File(s5);
if (!file2.isDirectory())//如果目标文件夹不存在
{
file2.mkdirs();//创建文件夹
}
bf.CopyFile(s2, s4 + s3[1]);//拷贝文件

Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss:SS");
String dt = sdf.format(date);
String msg = dt + "    " + s2 + "\n";
bf.logs(msg);
}
}
}

//计算所用的总时间
Date dt2 = new Date();
long tmp2 = dt2.getTime ();
long tmp3 = tmp2 - tmp1;
long tmp4 = tmp3/1000;
double tmp5 = 0;
String tmp6 = "";

if (tmp4 >= 60 && tmp4< 3600)
{
tmp5 = Double.valueOf ( tmp4 )/60;
tmp6 = String.format ( "%.2f" , tmp5 ) + " 分钟";
}else if (tmp4 >= 3600)
{
tmp5 = Double.valueOf ( tmp4 )/3600;
tmp6 = String.format ( "%.2f" , tmp5 ) + " 小时";
}else
{
tmp5 = tmp4;
tmp6 = tmp5 + " 秒";
}
//计算完毕


System.out.println("\n\n所有文件备份完毕,耗时:" + tmp6);
System.out.println ("需要备份的文件总数:" + bf.will);
System.out.println("备份成功的文件数:" + bf.total);
System.out.println("备份失败的文件数:" + bf.fail);

//
double db = Double.valueOf(bf.total_size);
double db2 = 0;
String tmp7 = "";
if ( db >= 1024000000000.0)
{
db2 = db/1024/1024/1024;
tmp7 = String.format("%.2f", db2) + " GB";
}else if (db >= 1024000 && db < 1024000000)
{
db2 = db/1024/1024;
tmp7 = String.format("%.2f", db2) + " MB";
}else if ( db >= 1024 && db < 1024000 )
{
db2 = db/1024;
tmp7 = String.format("%.2f", db2) + " KB";
}
System.out.println("备份成功的文件总大小:" + tmp7);
//备份完毕

File file = new File("tmp.sh");
if (file.exists ())
{
file.delete ();
}
}






/*
* 获取配置文件内容
*/
String getDirs() throws Exception
{
String result = "";
StringBuffer sb = new StringBuffer();


File file = new File("backupfiles.conf");
if (!file.exists())
{
System.out.println("Error!配置文件“backupfiles.conf”不存在!");
System.out.println("你必须把配置文件放在跟jar文件同一个目录下,并注意文件名的大小写必须正确!");
System.exit(1);
}
FileInputStream fis = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);

String s = br.readLine();
while (s != null)
{
String[] s2 = s.split("=");
char[] c = s.toCharArray();

if (c.length > 0 && c[0] != '#')
{
if (s2.length == 2)
{
this.dir.put(s2[0].trim(), s2[1].trim());
}else
{
sb.append(s + "\n");
}
}

s = br.readLine();
}

br.close();
isr.close();
fis.close();

result = sb.toString();
return result;
}





/*
* 检查是否是文件夹,是则返回1,不是则返回0
*/
int checkDir(String dir) throws Exception
{
int result = 0;
File file = new File(dir);
if (file.isDirectory())
{
result = 1;
}

return result;
}





/*
* 记录错误信息
*/
void errLogs(String msg) throws Exception
{
File file = new File ("err.log");
FileOutputStream fos = new FileOutputStream(file,true);
OutputStreamWriter osw = new OutputStreamWriter(fos);
BufferedWriter bw = new BufferedWriter(osw);
bw.write(msg);
bw.flush();


bw.close();
osw.close();
fos.close();
}





/*
* 记录备份信息
*/
void logs(String msg) throws Exception
{
File file = new File ("backupfiles.log");
FileOutputStream fos = new FileOutputStream(file,true);
OutputStreamWriter osw = new OutputStreamWriter(fos);
BufferedWriter bw = new BufferedWriter(osw);
bw.write(msg);
bw.flush();


bw.close();
osw.close();
fos.close();
}






/*
* 检查是否是文件,是则返回1,不是则返回0
*/
int checkFile(String file) throws Exception
{
int result = 0;
File file2 = new File(file);
if (file2.isFile())
{
result = 1;
}
return result;
}




/*
* 获取源端目录下所有文件夹
* srcdir是目录名,不是文件名
* */
ArrayList<String> getSrcDirs(String srcdir) throws Exception
{
ArrayList<String> result = new ArrayList<String>();

File file = new File(srcdir);
String[] src = file.list();

for (String s : src)
{
File file2 = new File(srcdir + File.separator + s);
if (file2.isDirectory())
{
result.add(srcdir + File.separator + s);
ArrayList<String> tmp = new ArrayList<String>();
tmp = this.getSrcDirs(srcdir + File.separator + s);
for (String s2 : tmp)
{
result.add(s2);
}
}
}

return result;
}




/*
* 获取源端目录下所有的文件
* srcdir是目录名,不是文件名
*/
ArrayList<String> getSrcFiles(String srcdir) throws Exception
{
ArrayList<String> result = new ArrayList<String>();

File file = new File(srcdir);
String[] src = file.list();

for (String s : src)
{
File file2 = new File(srcdir + File.separator + s);
if (file2.isDirectory())
{
ArrayList<String> tmp = new ArrayList<String>();
tmp = this.getSrcFiles(srcdir + File.separator + s);
for (String s2 : tmp)
{
result.add(s2);
}
}else if (file2.isFile())
{
result.add(srcdir + File.separator + s);
}
}

return result;
}







/*
* 拷贝文件
*/
int copyfile(String src,String targ) throws Exception
{
int result = 0;
File src_file = new File(src);
File targ_file = new File(targ);

System.out.print("开始备份文件:" + src + "...");
try
{
FileInputStream fis = new FileInputStream(src_file);
FileOutputStream fos = new FileOutputStream(targ_file);
// long filesize = src_file.length();
// long read = 1024;
//byte[] bt = new byte[1024];//一次读取1KB的内容
int a = fis.read();

while (a != -1)
{
fos.write(a);
fos.flush();
a = fis.read();

//int i = (int)((read + 0.0)/(filesize + 0.0) * 100);
//System.out.print("开始拷贝文件:" + src + "..." + i + "%\r");//打印文件拷贝进度
//read = read + 1024;
}
//fos.flush();
fos.close();
fis.close();
System.out.println("OK");
this.total++;
}catch (Exception e)
{
result = 1;
System.out.println("False");


Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss:SS");
String dt = sdf.format(date);
String msg = dt + "    " + e.toString() + "\n";
this.errLogs(msg);
}

return result;
}









/**
* 调用系统命令拷贝文件
* @param src
* @param targ
* @return
* @throws Exception
*/
int CopyFile(String src,String targ) throws Exception
{
int result = 0;

String s1 = File.separator;
Date dt3 = new Date();
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss:SS");

File src_file = new File(src);
long src_size = src_file.length();
this.total_size += src_size;
double size = Double.valueOf(src_size);
if ( size >= 1000000000)
{
size = size/1024/1024/1024;
System.out.print(sdf2.format ( dt3 ) + "  Backup," + this.total + ":" + src + ",size = " + String.format("%.2f", size) + " GB ...");
}else if (size >= 1000000 && size < 1000000000)
{
size = size/1024/1024;
System.out.print(sdf2.format ( dt3 ) + "  Backup," + this.total + ":" + src + ",size = " + String.format("%.2f", size) + " MB ...");
}else if (size >= 1000 && size < 1000000)
{
size = size/1024;
System.out.print(sdf2.format ( dt3 ) + "  Backup," + this.total + ":" + src + ",size = " + String.format("%.2f", size) + " KB ...");
}else
{
System.out.print(sdf2.format ( dt3 ) + "  Backup," + this.total + ":" + src + ",size = " + size + " B ...");
}

if (s1.equals ( "\\" ))
{
String s2 = "";
String[] s3 = targ.split ( "\\\\" );
for (int i = 0; i < s3.length - 1; i ++)
{
s2 += s3[i] + "\\";
}
String cmd = "xcopy /Y \"" + src + "\" \"" + s2 + "\"";
Runtime rt = Runtime.getRuntime ();
try
{
Process p = rt.exec ( cmd );
if (p.waitFor () == 0)
{
System.out.println("OK");
this.total++;
}else
{
result = 1;
System.out.println("False");

this.fail++;

Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss:SS");
String dt = sdf.format(date);

String err = "";
BufferedInputStream in = new BufferedInputStream(p.getInputStream());//捕获系统命令打印出来的错误信息
BufferedReader inBr = new BufferedReader(new InputStreamReader(in));
String lineStr = "";
while ((lineStr = inBr.readLine()) != null)
{
err += lineStr;
}
String msg = dt + "  " + err + ",cmd=" + cmd + "\n";
this.errLogs(msg);
}
}catch(Exception e)
{
result = 1;
System.out.println("False");

Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss:SS");
String dt = sdf.format(date);
String msg = dt + "    " + e.toString() + "\n";
this.errLogs(msg);
}

}else if (s1.equals ( "/" ))
{
String s2 = "";
String[] s3 = targ.split ( "/" );
for (int i = 0; i < s3.length - 1; i ++)
{
if ( i == s3.length - 1)
{
s2 += s3[i];
}else
{
s2 += s3[i] + "/";
}
}
src = src.replace(" ", "\\ ");
s2 = s2.replace(" ", "\\ ");
String cmd = "cp " + src + " " + s2;

if (src.contains ( " " ) || targ.contains ( " " ))
{
File tmp1 = new File("tmp.sh");
String path = tmp1.getAbsolutePath ();
FileOutputStream fos = new FileOutputStream(tmp1);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos));
String tmp2 = "#!/bin/bash\n";
bw.write ( tmp2 );
bw.flush ();
bw.write ( cmd + "\n");
bw.flush ();
bw.close ();
fos.close ();

Runtime rt = Runtime.getRuntime ();
Process p = rt.exec ( "chmod 755 " + path );
if (p.waitFor () != 0)
{
System.out.println("False");

this.fail++;

Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss:SS");
String dt = sdf.format(date);

String err = "";
BufferedInputStream in = new BufferedInputStream(p.getInputStream());//捕获系统命令打印出来的错误信息
BufferedReader inBr = new BufferedReader(new InputStreamReader(in));
String lineStr;
while ((lineStr = inBr.readLine()) != null)
{
err += lineStr;
}
String msg = dt + "  " + err + ",cmd=" + cmd + "\n";
this.errLogs(msg);
return result = 1;
}
cmd = path;
}
//System.out.println("cmd = " + cmd);
Runtime rt = Runtime.getRuntime ();
try
{
Process p = rt.exec ( cmd );
if (p.waitFor () == 0)
{
System.out.println("OK");
this.total++;
}else
{
result = 1;
System.out.println("False");

this.fail++;

Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss:SS");
String dt = sdf.format(date);

String err = "";
BufferedInputStream in = new BufferedInputStream(p.getInputStream());//捕获系统命令打印出来的错误信息
BufferedReader inBr = new BufferedReader(new InputStreamReader(in));
String lineStr;
while ((lineStr = inBr.readLine()) != null)
{
err += lineStr;
}
String msg = dt + "  " + err + ",cmd=" + cmd + "\n";
this.errLogs(msg);
}
}catch(Exception e)
{
result = 1;
System.out.println("False");

Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss:SS");
String dt = sdf.format(date);
String msg = dt + "  " + e.toString() + "\n";
this.errLogs(msg);
}
}
return result;
}
}

================================分割线==============================


软件运行状态截图