我在之前的公司里工作的时候,他们要求我做一个能够分析IIS日志的程序,可我做来做去,也只能做到,1个G的文件读取在140秒左右。愁了很久,想到了用多线程读取大文件的方法,又发现文件读取流可以有很多个,于是我就开始编写,写出来,其效率 4核CPU,可以达到14秒,提高了10倍。

而且据我测试发现,我4个CPU,用8个线程读取效率最高,所以我想会不会是一个CPU挂2个文件流效率最高,故基本逻辑是这样的,我根据CPU核数,将文件分成8块,分成8块的时候,必定出现,一行被截断的情况,针对这种情况,我采用一次初查,根据8个位点,倒着查出'\n'符号,查到了这个符号,那么,'\n'之前(包括'\n')都是完整的行数,这样就能准确的放置出8个位置,然后用多线程和Stream中的Postion定位,就可以分出8块。

之所以没用StreamReader,是因为Stream有1024字节的缓冲区,会使得位置无法读取准确。

下面是代码,因需求不同,故用抽象类来表示,(注:我将初查也用抽象方法表示,以便增强其扩展性)

  1  using System;
  2 using System.Collections.Generic;
  3 using System.Text;
  4 using System.Threading;
  5 using System.IO;
  6 namespace CommonLib.Threading.IO.ReadFile
  7 {
  8     /// <summary>
  9     /// 多线程文件读取器
 10     /// </summary>
 11     public abstract class FileReader
 12     {
 13         private string filePath;
 14         private List<FileReadPoint> readPoint=new List<FileReadPoint>();
 15         private bool isStart;
 16         private int threadCompleteCount;
 17         public event EventHandler FileReadEnd;//文件读取完成
 18         public bool IsStart
 19         {
 20             get { return isStart; }
 21         }
 22         public string FilePath
 23         {
 24             get { return filePath; }
 25         }
 26         private FileReader()
 27         {
 28         }
 29         public FileReader(string filePath)
 30         {
 31             this.filePath = filePath;
 32         }
 33         /// <summary>
 34         /// 获取读取文件的起始点和结束点
 35         /// 文件起始点会在参数point中给出
 36         /// </summary>
 37         /// <param name="point">读取文件的起始点和结束点</param>
 38         /// <param name="stream">文件流</param>
 39         /// <param name="length">文件长度</param>
 40         protected abstract void GetPoint(FileReadPoint point,FileStream stream,long length);
 41         /// <summary>
 42         /// 设置文件读取起始点
 43         /// </summary>
 44         /// <param name="stream"></param>
 45         /// <returns></returns>
 46         protected virtual int SetStartPoint(FileStream stream)
 47         {
 48             return 0;
 49         }
 50         /// <summary>
 51         /// 对已用多线程分块读取的文件做的处理
 52         /// </summary>
 53         /// <param name="threadStream"></param>
 54         protected abstract void DoFileRead(ThreadStream threadStream);
 55
 56         /// <summary>
 57         /// 初始化分块读取文件的点
 58         /// </summary>
 59         /// <returns></returns>
 60         public bool Create()
 61         {
 62             FileInfo fileInfo = new FileInfo(filePath);
 63             fileInfo.Refresh();
 64             if (fileInfo.Exists)
 65             {
 66                 filePath = fileInfo.FullName;
 67                 using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
 68                 {
 69                     if (readPoint.Count != 0)
 70                     {
 71                         readPoint.Clear();
 72                     }
 73                     long startPoint = SetStartPoint(stream);
 74                     long length = stream.Length;
 75                     while (startPoint < length)
 76                     {
 77                         stream.Position = startPoint;
 78                         FileReadPoint fPoint = new FileReadPoint();
 79                         fPoint.StartPoint = startPoint;
 80                         GetPoint(fPoint, stream, length);
 81                         if (fPoint.StartPoint + fPoint.ReadCount > length)
 82                         {
 83                             fPoint.ReadCount = length - fPoint.StartPoint;
 84                         }
 85                         readPoint.Add(fPoint);
 86                         startPoint = fPoint.StartPoint + fPoint.ReadCount;
 87                     }
 88                 }
 89                 return true;
 90             }
 91             else
 92             {
 93                 return false;
 94             }
 95         }
 96         /// <summary>
 97         /// 启动多线程文件读取
 98         /// </summary>
 99         public void StartRead()
100         {
101             if (!isStart)
102             {
103                 threadCompleteCount = 0;
104                 foreach (FileReadPoint fp in readPoint)
105                 {
106                     Thread thread = new Thread(OnReadFile);
107                     thread.IsBackground = true;
108                     thread.SetApartmentState(ApartmentState.MTA);
109                     thread.Start(fp);
110                 }
111                 isStart = true;
112             }
113         }
114
115
116         [MTAThread()]
117         private void OnReadFile(object obj)
118         {
119             FileReadPoint fp = obj as FileReadPoint;
120             if (fp != null)
121             {
122                 using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
123                 {
124                     stream.Position = fp.StartPoint;
125                     ThreadStream threadStream = new ThreadStream(stream, fp);
126                     DoFileRead(threadStream);
127                 }
128             }
129             if (FileReadEnd != null)
130             {
131                 lock (readPoint)
132                 {
133                     threadCompleteCount++;
134                     if (threadCompleteCount == readPoint.Count)
135                     {
136                         FileReadEnd(this, new EventArgs());
137                     }
138                 }
139             }
140         }
141
142     }
143
144     public class FileReadPoint
145     {
146         private long startPoint = 0L;
147
148         public long StartPoint
149         {
150             get { return startPoint; }
151             set { startPoint = value; }
152         }
153
154         private long readCount = 1L;
155
156         public long ReadCount
157         {
158             get { return readCount; }
159             set {
160                 if (value >= 1)
161                 {
162                     readCount = value;//readCount必须大于1
163                 }
164             }
165         }
166     }
167
168     public sealed class ThreadStream
169     {
170         private int MAXBLOCK = 1024 * 1024 * 4;
171
172         private FileStream fileStream;
173         private FileReadPoint fPoint;
174         private long currentCount = 0L;
175
176         public FileReadPoint FPoint
177         {
178             get { return fPoint; }
179         }
180
181         private ThreadStream()
182         {
183         }
184
185         public ThreadStream(FileStream stream, FileReadPoint point)
186         {
187             this.fileStream = stream;
188             this.fPoint = point;
189         }
190
191         /// <summary>
192         /// 读取剩余的所有字节
193         /// </summary>
194         /// <returns></returns>
195         public byte[] ReadAll()
196         {
197             if (currentCount < fPoint.ReadCount)
198             {
199                 long lastCount = fPoint.ReadCount - currentCount;
200                 byte[] data = new byte[lastCount];
201                 long currentDataIndex = 0L;
202                 while (lastCount > MAXBLOCK)
203                 {
204                     AddData(MAXBLOCK,data, currentDataIndex);
205                     lastCount = lastCount - MAXBLOCK;
206                     currentDataIndex += MAXBLOCK;
207                 }
208                 if (lastCount > 0)
209                 {
210                     AddData((int)lastCount, data, currentDataIndex);
211                 }
212                 currentCount = fPoint.ReadCount;
213                 return data;
214             }
215             else
216             {
217                 return null;
218             }
219         }
220
221         /// <summary>
222         /// 分块读取字节
223         /// </summary>
224         /// <param name="block"></param>
225         /// <returns></returns>
226         public byte[] Read(int block)
227         {
228             if (currentCount < fPoint.ReadCount)
229             {
230                 int currentBlock = block;
231                 if (currentCount + block > fPoint.ReadCount)
232                 {
233                     currentBlock = (int)(fPoint.ReadCount - currentCount);
234                 }
235                 byte[] data = new byte[currentBlock];
236                 fileStream.Read(data, 0, data.Length);
237                 currentCount += currentBlock;
238                 return data;
239
240             }
241             else
242             {
243                 return null;
244             }
245         }
246
247         private void AddData(int block,byte[] data, long currentDataIndex)
248         {
249             byte[] cutData = Read(block);
250             Array.Copy(cutData, 0, data, currentDataIndex, cutData.Length);
251         }
252
253     }
254 }

View Code

转载于:https://www.cnblogs.com/zmx-mk/p/FileOnThread.html

多线程读取大文件,尤其是对日志文件分析很有用。相关推荐

  1. php删除oracle数据记录日志文件,Oracle手动切换日志文件和清空日志文件

    日志文件组是循环使用的,当一组日志文件被写满时,Oracle系统自动的切换到下一组日志文件.在需要的时候,数据库管理员也可以手 Oracle切换日志文件组 日志文件组是循环使用的,当一组日志文件被写满 ...

  2. 怎样下载linux的日志文件,Linux常见的日志文件及查看命令

    Linux常见日志和常用命令 Linux 日志都以明文形式存储,所以我们不需要特殊的工具就可以搜索和阅读它们.Linux 日志存储在 /var/log 目录中,我们可以编写脚本,来扫描这些日志,并基于 ...

  3. java如何读取自定义log4j2_spring boot自定义log4j2日志文件的实例讲解

    背景:因为从 spring boot 1.4开始的版本就要用log4j2了,支持的格式有json和xml两种格式,此次实践主要使用的是xml的格式定义日志说明. spring boot 1.5.8.R ...

  4. 所属文件不可访问_日志文件写入失败(permission denied)

    用过Laravel的小伙伴一开始安装完框架后可能都遇到过daily 日志文件写入失败的问题,接下来我们就来详细说下日志文件写入失败的原因以及对应的解决方案. 在讲这个问题之前可能需要简单介绍下Linu ...

  5. oracle 安装时的日志文件,oracle10g安装的日志文件 Oracle10g怎么查看操作日志

    如何查看oracle 10g 的操作日志 归档模式下怎么查询oracle 10g归档日志存放的路径? SQL> select name from v$archived_log; NAME /u0 ...

  6. 数据库服务器备份日志文件,数据库服务器备份日志文件

    数据库服务器备份日志文件 内容精选 换一换 使用自定义脚本实现数据库备份完成后,可以通过如下操作验证数据库备份结果是否成功.本章节以SQL_SERVER数据库为例进行验证. 业界对备份一致性的定义包括 ...

  7. 服务器查看数据库日志文件,服务器数据库查看日志文件

    服务器数据库查看日志文件 内容精选 换一换 对于不同业务场景,通过在调整数据库的参数配置,可以有效提升服务器性能.使用如下配置文件参数启动数据库,默认配置文件路径为/etc/my.cnf, 其中MyS ...

  8. mysql日志文件名字_MySQL各类日志文件相关变量介绍

    文章转自:http://www.ywnds.com/?p=3721 查询所有日志的变量 1 mysql>show global variables like'%log%'; GLOBAL表示查全 ...

  9. linux日志文件存放目录,Log4j 日志文件Linux/Mac/Windows通用存放位置设置方法

    log4j1/log4j2中category的配置以及log的输出位置(windows和linux通用的log输出位置) 一.场景和需求 假设我现在有3个独立的用project(暂时用maven关联起 ...

最新文章

  1. 【ACM】杭电OJ 2040
  2. python装keras_python – 在anaconda中安装keras时出错. / p KER...
  3. java温度计的实现_echart 之实现温度计
  4. 未来5年,中国会有多少企业营收能达到1000亿美元以上?
  5. 计算机软件复用意义何在,2009计算机科学技术导论复习要点.pdf
  6. C语言从来都没有过时,你大爷终究是你大爷
  7. 《学C编程也可以卡通一点》一1.7变量的类型
  8. exc导入mysql phpcms_PHP如何将EXCEL导入MYSQL,急!!!急!!哪位大师能帮帮忙啊,给个详细代码...
  9. Acrobat Pro DC 2022 Mac(全能PDF工具)完美兼容m1
  10. svn合并分支到主干
  11. 8.声卡驱动02-自己实现alsa驱动-虚拟声卡-匹配
  12. 【Linux】Infiniband 驱动安装---(HCA光钎)---mlnx
  13. react-native 轮播组件 looped-carousel使用介绍
  14. 博客做外链不收录怎么办,如何利用博客做外链
  15. rabbitMQ队列解绑
  16. 垂直投影法分割验证码
  17. 屏幕坐标系转为笛卡尔坐标系
  18. 做中国强制性CCC认证需要多少钱
  19. Android中使用logger打印完整的okhttp网络请求和响应的所有相关信息(请求行、请求头、请求体、响应行、响应行、响应头、响应体)
  20. You do not have sufficient permissions to access the inventory ‘/u01/app/oraInventory‘.

热门文章

  1. zabbix4监控mysql_Zabbix4监控Mysql5.7
  2. 168输出为861java_AcWing 861. 二分图的最大匹配-java-关键处注释
  3. java mysql 动态sql_Java下拼接运行动态SQL语句
  4. 威客php,phpapp威客系统下载
  5. sails mysql_sails项目创建与常用基础操作总结
  6. Python数据分析学习笔记:Python数据可视化入门
  7. 【BZOJ3050】Seating,线段树
  8. 【codevs4654】【BZOJ2442】修剪草坪,第一次的单调队列,优化DP
  9. 9.霍夫变换:圆——圆的算法、投票使用技巧、优点和缺点_2
  10. 如何维持手机电池寿命_手机电池不耐用,都怪这些充电坏毛病