c#大文件分割過程

需求:性能

在項目開發中,咱們會遇到單個文件大小超過1TB的文件,這樣的文件只能進行單文件讀取,每每會形成讀取完成耗時過長,致使客戶在使用體驗過程當中不滿意。spa

爲了解決提高大文件的解析速度,我想到了先分割大文件爲小文件,以後進行並行多個文件同時解析入庫方案。code

那麼,怎麼才能夠把一個大文件分割爲多個小文件呢?orm

若是我按照大小來控制分割出來的小文件,會形成文件的丟失問題,若是按照行數來分割,一行一行進行讀取務必會形成分割文件耗時過長。blog

討論:若是一個1TB的文件,咱們按照大小來控制文件個數,假設每一個分割出來的文件大小爲200M,這樣的話1TB分割出來約5200個文件,這樣子的話最多形成約10000行信息被破壞,能夠忽略不計。開發

因此咱們爲了減小分割文件帶來的耗時時間長度,採起分割方案採用定長控制分割出來的文件大小。input

  • 實現方案1:一次性讀取1M,直到讀取到200M爲止,開始寫入下一個分割文件。
 1  using (FileStream readerStream = new FileStream(file, FileMode.Open, FileAccess.Read))
 2             {
 3                 // 若是大於1GB
 4                 using (BinaryReader reader = new BinaryReader(readerStream))
 5                 {
 6                     int fileCursor = 0;
 7                     int readerCursor = 0;
 8                     char[] buffer = new char[1024 * 1024];
 9                     int length = 0;
10 
11                 NextFileBegin:
12                     string filePath = string.Format(splitFileFormat, fileCursor);
13 
14                     Console.WriteLine("開始讀取文件【{1}】:{0}", filePath, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
15                     using (FileStream writerStream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write))
16                     {
17                         using (BinaryWriter writer = new BinaryWriter(writerStream))
18                         {
19                             while ((length = reader.Read(buffer, 0, buffer.Length)) > 0)
20                             {
21                                 readerCursor++;
22 
23                                 writer.Write(buffer, 0, length);
24 
25                                 if (readerCursor >= splitFileSize)
26                                 {
27                                     Console.WriteLine("結束讀取文件【{1}】:{0}", filePath, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
28 
29                                     readerCursor = 0;
30                                     fileCursor++;
31 
32                                     goto NextFileBegin;
33                                 }
34                             }
35                         }
36                     }
37                 }
38             }
  • 實現方案2:一次性讀取200M,當即寫入分割文件,開始下一個分割文件操做。
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.IO;
 6 using System.Configuration;
 7 
 8 namespace BigFileSplitTest
 9 {
10     class Program
11     {
12         static void Main(string[] args)
13         {
14             /*
15              *  <!--是否開啓大文件分隔策略-->
16                 <add key="BigFile.Split" value="true"/>
17                 <!--當文件大於這個配置項時就執行文件分隔,單位:GB -->
18                 <add key="BigFile.SplitMinFileSize" value="10" />
19                 <!--當執行文件分割時,每一個分隔出來的文件大小,單位:MB -->
20                 <add key="BigFile.SplitFileSize" value="200"/>
21              *  <add key="BigFile.FilePath" value="\\172.x1.xx.xx\文件拷貝\xx\FTP\xx\2016-04-07\x_20160407.txt"/>
22                 <add key="BigFile.FileSilitPathFormate" value="\\172.x1.xx.xx\文件拷貝\liulong\FTP\xx\2016-04-07\x_20160407{0}.txt"/>
23              */
24 
25             string file = ConfigurationManager.AppSettings.Get("BigFile.FilePath");
26             string splitFileFormat = ConfigurationManager.AppSettings.Get("BigFile.FileSilitPathFormate");
27             int splitMinFileSize = Convert.ToInt32(ConfigurationManager.AppSettings.Get("BigFile.SplitMinFileSize")) * 1024 * 1024 * 1204;
28             int splitFileSize = Convert.ToInt32(ConfigurationManager.AppSettings.Get("BigFile.SplitFileSize")) * 1024 * 1024;
29 
30             FileInfo fileInfo = new FileInfo(file);
31             if (fileInfo.Length > splitMinFileSize)
32             {
33                 Console.WriteLine("斷定結果:須要分隔文件!");
34             }
35             else
36             {
37                 Console.WriteLine("斷定結果:不須要分隔文件!");
38                 Console.ReadKey();
39                 return;
40             }
41 
42             int steps = (int)(fileInfo.Length / splitFileSize);
43             using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
44             {
45                 using (BinaryReader br = new BinaryReader(fs))
46                 {
47                     int couter = 1;
48                     bool isReadingComplete = false;
49                     while (!isReadingComplete)
50                     {
51                         string filePath = string.Format(splitFileFormat, couter);
52                         Console.WriteLine("開始讀取文件【{1}】:{0}", filePath, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
53                        
54                         byte[] input = br.ReadBytes(splitFileSize);
55                         using (FileStream writeFs = new FileStream(filePath, FileMode.Create))
56                         {
57                             using (BinaryWriter bw = new BinaryWriter(writeFs))
58                             {
59                                 bw.Write(input);
60                             }
61                         }
62 
63                         isReadingComplete = (input.Length != splitFileSize);
64                         if (!isReadingComplete)
65                         {
66                             couter += 1;
67                         }
68                         Console.WriteLine("完成讀取文件【{1}】:{0}", filePath, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
69                     }
70                 }
71             }
72 
73 
74             Console.WriteLine("分隔完成,請按下任意鍵結束操做。。。");
75             Console.ReadKey();
76 
77         }
78     }
79 }

從實驗結果發現:方案一的性能較方案二的性能約耗時10倍。string

具體緣由爲何?it

請你思考下:io

一次性讀取1M,直到讀取到200M爲止,開始寫入下一個分割文件。

一次性讀取200M,當即寫入分割文件,開始下一個分割文件操做。

相關文章
相關標籤/搜索