zoukankan      html  css  js  c++  java
  • c#大文件分割过程

    需求:

    在项目开发中,我们会遇到单个文件大小超过1TB的文件,这样的文件只能进行单文件读取,往往会造成读取完成耗时过长,导致客户在使用体验过程中不满意。

    为了解决提升大文件的解析速度,我想到了先分割大文件为小文件,之后进行并行多个文件同时解析入库方案。

    那么,怎么才可以把一个大文件分割为多个小文件呢?

    如果我按照大小来控制分割出来的小文件,会造成文件的丢失问题,如果按照行数来分割,一行一行进行读取务必会造成分割文件耗时过长。

    讨论:如果一个1TB的文件,我们按照大小来控制文件个数,假设每个分割出来的文件大小为200M,这样的话1TB分割出来约5200个文件,这样子的话最多造成约10000行信息被破坏,可以忽略不计。

    所以我们为了减少分割文件带来的耗时时间长度,采取分割方案采用定长控制分割出来的文件大小。

    • 实现方案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文件拷贝xxFTPxx2016-04-07x_20160407.txt"/>
    22                 <add key="BigFile.FileSilitPathFormate" value="\172.x1.xx.xx文件拷贝liulongFTPxx2016-04-07x_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倍。

    具体原因为什么?

    请你思考下:

    一次性读取1M,直到读取到200M为止,开始写入下一个分割文件。

    一次性读取200M,立即写入分割文件,开始下一个分割文件操作。

  • 相关阅读:
    ddl(数据定义语言) ,dml (数据操控语言),dcl(数据控制语言)
    集合框架
    泛型(模拟list)
    Clone
    线程问题以及调用
    面向对象(封装、继承、多态、抽象)
    SpringMVC的四个核心接口
    VUE项目报错 This is probably not a problem with npm. There is likely additional logging output above.
    debian java8 cacerts 证书的丢失
    yii2 ,thinkphp的伪静态
  • 原文地址:https://www.cnblogs.com/yy3b2007com/p/5558877.html
Copyright © 2011-2022 走看看