標籤:des winform style blog http color 使用 os
大檔案拷貝(檔案流的使用)、檔案編碼
首先說一下大檔案拷貝和檔案流,因為電腦的記憶體資源是有限的,面對幾個G甚至更大的檔案,需要通過程式來完成拷貝,就需要用到檔案流(因為我們無法做到把檔案一次性載入到記憶體中;事實上,記憶體也不允許這麼幹),所以在C#中出現了記憶體流這個東西。先看下面的內容,File類中的常用讀取檔案方法會將檔案內容一次性全部載入到記憶體中:
1 string sPath = @"C:\Users\Chens-PC\Desktop\Nginx.txt";2 //File類的ReadAllBytes()方法會將常值內容一次性讀取到記憶體中,然後以byte數組返回(同時關閉檔案)。3 byte[] bteData = File.ReadAllBytes(sPath);4 //File類的ReadAllLines()方法會將常值內容一次性逐行讀取到記憶體中,然後以string數組返回(同時關閉檔案),它的重載能指定讀取時使用的編碼。5 string[] strData = File.ReadAllLines(sPath);6 //File類的ReadAllText()方法會將常值內容一次性讀取到記憶體中,然後以string字串返回(同時關閉檔案),它的重載能指定讀取時使用的編碼。7 string sData = File.ReadAllText(sPath);
註:上面的代碼,在傳參時為Encoding.Default(表示與當前作業系統編碼一致,一般是簡體中文ANSI),而DotNet建立文字檔編碼為UTF-8.
在進行大檔案拷貝之前,先說一下,如果使用檔案流(FileStream):
1 #region 通過檔案流寫檔案 2 string sMsg = "風兒吹來了童年的一幅畫 你陪著我在那過家家 竹林是我們的家 竹葉是你送我的花 抬頭見你笑得那麼的無暇"; 3 using (FileStream fsWrite = new FileStream("msg.txt", FileMode.Create, FileAccess.Write)) 4 { 5 byte[] bteData = System.Text.Encoding.UTF8.GetBytes(sMsg); 6 fsWrite.Write(bteData, 0, bteData.Length); 7 fsWrite.Flush(); 8 } 9 Console.WriteLine("檔案寫入完畢!");10 #endregion
1 #region 通過檔案流讀檔案 2 using (FileStream fsRead = new FileStream("msg.txt", FileMode.Open, FileAccess.Read)) 3 { 4 byte[] bteData = new byte[fsRead.Length]; 5 fsRead.Read(bteData, 0, bteData.Length); 6 //將byte[]數群組轉換成字串時才需要指定編碼。 7 string s = System.Text.Encoding.UTF8.GetString(bteData); 8 Console.WriteLine(s); 9 }10 #endregion
1.大檔案拷貝:
思路:考慮到大檔案的拷貝要邊讀邊寫,故要建立2個檔案流(一個讀,一個寫),案例的代碼如下(winform照樣適用):
1 #region 大檔案拷貝2 string sSource = @"F:\系統\cn_windows_7_ultimate_with_sp1_x86_dvd_618763.iso";3 string sTarget = @"E:\C#練習第一天\windows_7.iso";4 5 CopyBigFile(sSource, sTarget);6 Console.ReadKey();7 #endregion
View Code
1 private static void CopyBigFile(string sSource, string sTarget) 2 { 3 using (FileStream fsRead=new FileStream(sSource,FileMode.Open,FileAccess.Read)) 4 { 5 using (FileStream fsWrite=new FileStream(sTarget,FileMode.Create,FileAccess.Write)) 6 { 7 //定義緩衝區 8 byte[] bteData = new byte[12 * 1024 * 1024]; 9 int r = fsRead.Read(bteData, 0, bteData.Length);10 while (r>0)11 {12 fsWrite.Write(bteData, 0, r);13 double d = 100 * (fsWrite.Position / (double)fsRead.Length);14 Console.WriteLine("{0}%", d);15 r = fsRead.Read(bteData, 0, bteData.Length);16 }17 Console.WriteLine("複製大檔案成功");18 }19 }20 }
View Code
說明:
快速建立檔案流的方式:(不要在迴圈中建立檔案流,放在迴圈外,效率問題)
FileStream fsRead=File.OpenRead(sPath); //快速建立讀取流
FileStream fsWrite=File.OpenWrite(sPath); //快速建立寫入流
FileStream fs=File.Open(sPath,FileMode.OpenOrCreate); //建立檔案流
上面的3個方法只是微軟對(大檔案拷貝中建立檔案流方法的封裝,簡化代碼編寫的方式)。
最後再來討論檔案讀寫亂碼的問題(檔案編碼):
下面是常用的文字檔編碼:
1.GB2312編碼:相容ASCII碼錶,英文字元用1個位元組表示(位元組用正數來表示),中文用2個位元組表示(位元組用負數來表示)。
2.GBK編碼:相容GB2312編碼。中文用2個位元組表示(第1個位元組用負數,第2個位元組用緊跟其後的正數)。
3.Unicode:國際碼錶,中英文都佔2個位元組。
4.UTF-8:國際碼錶,英文佔1個位元組,中文佔3個位元組。
因為各種編碼儲存資料格式不一致,如果讀寫編碼不同就會亂碼,解決亂碼的途徑就是讓讀寫操作時保證編碼一致即可。
檔案編碼的BOM頭:
時常在讀取檔案時用檔案的編碼,有時前面會多一個問號,這是因為BOM頭造成的File.ReadAllBytes().(不準確,有的編碼帶BOM頭,有的則不帶)
2.StreamReader與StreamWriter:
應用情境:在使用FileStream進行大檔案拷貝的時候,因為中文佔2個位元組,那麼有可能產生讀漢字讀一半的情況,進而產生亂碼。
StreamReader,逐行讀取文字檔。ReadLine()、EndOfStream. 注意:指定編碼!
ReadToEnd用於從當前位置一直讀到最後,內容大的話會佔記憶體;每次調用都往下走,不能無意中調用了兩次.
ReadLine讀取一行,如果到了末尾,則返回null.
StreamWriter,逐行寫入文字檔。
WriteLine,將字串寫入檔案中的當前行。
3.壓縮流GZipStream:
1>壓縮: 1.建立讀取流File.OpenRead() 2.建立寫入流File.OpenWrite(); 3.建立壓縮流new GZipStream();將寫入流作為參數與。 4.每次通過讀取流讀取一部分資料,通過壓縮流寫入。
1 //GZipStream就是對FileStream的又一個封裝 2 //將文字檔1.txt壓縮 3 //1.建立讀取文字檔的流 4 using (FileStream fsRead = File.OpenRead("1.txt")) 5 { 6 //2.建立寫入文字檔的流 7 using (FileStream fsWrite = File.OpenWrite("yasuo.txt")) 8 { 9 //3.建立壓縮流10 using (GZipStream zipStream = new GZipStream(fsWrite, CompressionMode.Compress))11 {12 //4.每次讀取1024byte13 byte[] byts = new byte[1024];14 int len = 0;15 while ((len = fsRead.Read(byts, 0, byts.Length)) > 0)16 {17 //通過壓縮流寫入檔案18 zipStream.Write(byts, 0, len);19 }20 }21 }22 }23 Console.WriteLine("ok");24 Console.ReadKey();
2>解壓:
1.建立讀取流:File.OpenRead() 2.建立壓縮流:new GZipStream();將讀取流作為參數 3.建立寫入流File.OpenWrite(); 4.每次通過壓縮流讀取資料,通過寫入流寫入資料。
1 using (FileStream fsRead = File.OpenRead("yasuo.txt")) 2 { 3 4 using (GZipStream gzipStream = new GZipStream(fsRead, CompressionMode.Decompress)) 5 { 6 using (FileStream fsWrite = File.OpenWrite("jieya.txt")) 7 { 8 9 byte[] byts = new byte[1024];10 int len = 0;11 while ((len = gzipStream.Read(byts, 0, byts.Length)) > 0)12 {13 fsWrite.Write(byts, 0, len);14 }15 16 }17 }18 }19 Console.WriteLine("ok");20 Console.ReadKey();