C#寫(xiě)差異文件備份工具的示例
大家是不是平常都有好多文件需要定期備份?如歌曲、視頻、文檔,代碼文件等等,如果經(jīng)常增加刪除修改文件,就需要定期備份,最早之前文件都不大的時(shí)候我都是手工先全部刪除,然后再全部拷貝,感覺(jué)比較保險(xiǎn)。后來(lái)有了很大的電影文件和很瑣碎的代碼文件之后,這樣搞太折磨人,就學(xué)網(wǎng)上說(shuō)的用Xcpoy組裝了一個(gè)批處理。學(xué)了C#后,感覺(jué)還是做一個(gè)GUI體驗(yàn)更好用起來(lái)更方便。至于專業(yè)的工具,還真沒(méi)怎么試過(guò),有點(diǎn)不放心吧,有好用的倒是可以試試?,F(xiàn)在先自己做一個(gè)用著吧。
關(guān)鍵代碼如下:
private async void btnBackUp_Click(object sender, EventArgs e) { string sourceDirectory = txtSource.Text; string targetDirectory = txtTarget.Text; if (sourceDirectory.ToLower() == targetDirectory.ToLower()) { Console.WriteLine("源目錄和備份目錄不能是同一目錄!"); MessageBox.Show("源目錄和備份目錄不能是同一目錄!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } DirectoryInfo diSource = new DirectoryInfo(sourceDirectory); // 源目錄 DirectoryInfo diTarget = new DirectoryInfo(targetDirectory); // 備份目錄 if (diTarget.Name != diSource.Name) diTarget = new DirectoryInfo(Path.Combine(diTarget.FullName, diSource.Name)); // 創(chuàng)建同名目錄 if (!diTarget.Exists) diTarget.Create(); // 如果該目錄已存在,則此方法不執(zhí)行任何操作 btnBackUp.Enabled = false; txtSource.Enabled = false; txtTarget.Enabled = false; lblWork.Text = "備份開(kāi)始!"; if (await CopyAllAsync(diSource, diTarget)) { lblWork.Text = "備份完成!"; MessageBox.Show("備份完畢!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } else lblWork.Text = "出現(xiàn)錯(cuò)誤!"; btnBackUp.Enabled = true; txtSource.Enabled = true; txtTarget.Enabled = true; btnBackUp.Focus(); } public async Task<bool> CopyAllAsync(DirectoryInfo source, DirectoryInfo target) { try { foreach (FileInfo fi in source.GetFiles()) // 復(fù)制最新文件 { Console.WriteLine(@"準(zhǔn)備復(fù)制文件 {0}\{1}", target.FullName, fi.Name); // Name不含路徑,僅文件名 FileInfo newfi = new FileInfo(Path.Combine(target.FullName, fi.Name)); if (!newfi.Exists || (newfi.Exists && fi.LastWriteTime > newfi.LastWriteTime)) { Console.WriteLine("正在復(fù)制文件 {0}", newfi.FullName); lblWork.Text = string.Format("正在復(fù)制文件 {0}", newfi.FullName); if (newfi.Exists && newfi.IsReadOnly) newfi.IsReadOnly = false; // 覆蓋或刪除只讀文件會(huì)產(chǎn)生異常:對(duì)路徑“XXX”的訪問(wèn)被拒絕 fi.CopyTo(newfi.FullName, true); // Copy each file into it's new directory } } foreach (FileInfo fi2 in target.GetFiles()) // 刪除源目錄沒(méi)有而目標(biāo)目錄中有的文件 { FileInfo newfi2 = new FileInfo(Path.Combine(source.FullName, fi2.Name)); if (!newfi2.Exists) { Console.WriteLine("正在刪除文件 {0}", fi2.FullName); lblWork.Text = string.Format("正在刪除文件 {0}", fi2.FullName); if (fi2.IsReadOnly) fi2.IsReadOnly = false; fi2.Delete(); // 沒(méi)有權(quán)限(如系統(tǒng)盤(pán)需管理員權(quán)限)會(huì)產(chǎn)生異常,文件不存在不會(huì)產(chǎn)生異常 } } foreach (DirectoryInfo di in source.GetDirectories()) // 復(fù)制目錄(實(shí)際上是創(chuàng)建同名目錄,和源目錄的屬性不同步) { Console.WriteLine(" {0} {1}", di.FullName, di.Name); // Name不含路徑,僅本級(jí)目錄名 Console.WriteLine(@"準(zhǔn)備創(chuàng)建目錄 {0}\{1}", target.FullName, di.Name); DirectoryInfo newdi = new DirectoryInfo(Path.Combine(target.FullName, di.Name)); if (!newdi.Exists) // 如果CopyAllAsync放在if里的bug: 只要存在同名目錄,則不會(huì)進(jìn)行子目錄和子文件的檢查和更新 { Console.WriteLine("正在創(chuàng)建目錄 {0}", newdi.FullName); lblWork.Text = string.Format("正在復(fù)制目錄 {0}", newdi.FullName); DirectoryInfo diTargetSubDir = target.CreateSubdirectory(di.Name); // 創(chuàng)建目錄 Console.WriteLine("完成創(chuàng)建目錄 {0}", diTargetSubDir.FullName); } if (await CopyAllAsync(di, newdi) == false) return false; ; // Copy each subdirectory using recursion } foreach (DirectoryInfo di2 in target.GetDirectories()) // 刪除源目錄沒(méi)有而目標(biāo)目錄中有的目錄(及其子目錄和文件) { DirectoryInfo newdi2 = new DirectoryInfo(Path.Combine(source.FullName, di2.Name)); if (!newdi2.Exists) { Console.WriteLine("正在刪除目錄 {0}", di2.FullName); lblWork.Text = string.Format("正在刪除目錄 {0}", di2.FullName); di2.Delete(true); // 只讀的目錄和文件也能刪除,如不使用參數(shù)則異常"目錄不是空的" } } return true; } catch (Exception e) { Console.WriteLine(e.Message); MessageBox.Show(e.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } }
注意事項(xiàng):
// 文件和目錄的創(chuàng)建日期為首次全新復(fù)制時(shí)的創(chuàng)建時(shí)間
// 文件復(fù)制后修改日期始終保持原先的不變,目錄的修改日期為首次全新復(fù)制時(shí)的創(chuàng)建時(shí)間(因?yàn)楸揪褪切陆?
// 單純的覆蓋不會(huì)改變修改時(shí)間和創(chuàng)建時(shí)間
// 文件發(fā)生的屬性變化全新復(fù)制時(shí)可以保留(無(wú)法通過(guò)更新時(shí)間判斷文件的屬性變化)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
今天測(cè)試,又發(fā)現(xiàn)一個(gè)bug,真是防不勝防,好在終于找到病根并解決了。
問(wèn)題出在 if (await CopyAllAsync(diSource, diTarget)) 這個(gè)地方,備份開(kāi)始后,lblWork.Text = "備份開(kāi)始!"; 結(jié)果發(fā)現(xiàn)標(biāo)簽的設(shè)置并不生效,然后界面很卡,不能拖動(dòng)窗口。在需要備份更新的文件特別多時(shí)感覺(jué)更明顯。
原來(lái),設(shè)置控件的Enabled屬性是立即生效,但控件的Text屬性并不是立即生效,就是UI界面不會(huì)立即更新,只是將設(shè)置信息加入了windows消息隊(duì)列,通常等所在的方法執(zhí)行完畢后才生效,但如果方法中該語(yǔ)句后面還有同類的設(shè)置,就會(huì)感覺(jué)不到它的生效,其實(shí)是生效了,只是先設(shè)為了一個(gè)值,然后又立即設(shè)為了另一個(gè)值,因?yàn)樘炝?,人眼看不出?lái)。同樣的原因,“正在復(fù)制文件XXX”也不即時(shí)顯示正在復(fù)制的文件信息。
然后,界面卡頓,是因?yàn)榭截惖臅r(shí)候執(zhí)行緊密運(yùn)算,但是CopyAllAsync(diSource, diTarget)方法并沒(méi)有在單獨(dú)的線程運(yùn)行,占用了UI線程,導(dǎo)致界面卡頓,改成下面這樣,完美解決:
lblWork.Text = "備份開(kāi)始!"; bool result = await Task.Run(() => CopyAllAsync(diSource, diTarget)); // 這兒是關(guān)鍵 if (result) // if (await CopyAllAsync(diSource, diTarget)) 開(kāi)始后界面會(huì)卡{ lblWork.Text = "備份完成!"; MessageBox.Show("備份完畢!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } else lblWork.Text = "出現(xiàn)錯(cuò)誤!";
以上就是C#寫(xiě)差異文件備份工具的示例的詳細(xì)內(nèi)容,更多關(guān)于c# 文件備份的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#使用Interlocked實(shí)現(xiàn)線程同步
今天小編就為大家分享一篇關(guān)于C#使用Interlocked實(shí)現(xiàn)線程同步,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-10-10C#實(shí)現(xiàn)語(yǔ)音視頻錄制-附demo源碼
在很多語(yǔ)言視頻軟件系統(tǒng)中,經(jīng)常有將實(shí)時(shí)的音頻或者是視頻錄制為文件保存到磁盤(pán)空間的需求,本篇給大家講C#實(shí)現(xiàn)語(yǔ)音視頻錄制-附demo源碼,感興趣的朋友一起來(lái)學(xué)習(xí)吧2015-08-08C#實(shí)現(xiàn)帶進(jìn)度條的ListView
這篇文章主要介紹了C#實(shí)現(xiàn)帶進(jìn)度條的ListView 的相關(guān)資料,需要的朋友可以參考下2016-02-02C#/C++ 通過(guò)ODBC連接OceanBase Oracle租戶的詳細(xì)過(guò)程
近期我們項(xiàng)目正處于將Oracle數(shù)據(jù)庫(kù)遷移到OceanBase Oracle租戶模式的階段,考慮到我們項(xiàng)目采用了C++和C#混合開(kāi)發(fā),并且使用了多種技術(shù),因此存在多種數(shù)據(jù)庫(kù)連接方式,C#連接OceanBase的案例相對(duì)較少,因此我特意記錄下這一過(guò)程,感興趣的朋友一起看看吧2024-05-05unity使用socket編程實(shí)現(xiàn)聊天室功能
這篇文章主要為大家詳細(xì)介紹了unity使用socket編程實(shí)現(xiàn)聊天室功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11C#實(shí)現(xiàn)在購(gòu)物車系統(tǒng)中生成不重復(fù)訂單號(hào)的方法
這篇文章主要介紹了C#實(shí)現(xiàn)在購(gòu)物車系統(tǒng)中生成不重復(fù)訂單號(hào)的方法,涉及C#中時(shí)間與字符串操作的相關(guān)技巧,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下2015-05-05深入探討C#中的const、readonly關(guān)鍵字
這篇文章主要介紹了深入探討C#中的const、readonly關(guān)鍵字,本文可以幫助你深刻理解這兩個(gè)關(guān)鍵字,而且是面試中最可能面試到的問(wèn)題哦,需要的朋友可以參考下2014-08-08C#機(jī)器入門(mén)學(xué)習(xí)之判斷日?qǐng)?bào)是否合格詳解
這篇文章主要給大家介紹了關(guān)于C#機(jī)器入門(mén)學(xué)習(xí)之判斷日?qǐng)?bào)是否合格的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用c#具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03C#使用表達(dá)式樹(shù)實(shí)現(xiàn)對(duì)象復(fù)制的示例代碼
這篇文章主要介紹了C#使用表達(dá)式樹(shù)實(shí)現(xiàn)對(duì)象復(fù)制,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-01-01