多线程读取大文件,尤其是对日志文件分析很有用。
我在之前的公司里工作的时候,他们要求我做一个能够分析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
多线程读取大文件,尤其是对日志文件分析很有用。相关推荐
- php删除oracle数据记录日志文件,Oracle手动切换日志文件和清空日志文件
日志文件组是循环使用的,当一组日志文件被写满时,Oracle系统自动的切换到下一组日志文件.在需要的时候,数据库管理员也可以手 Oracle切换日志文件组 日志文件组是循环使用的,当一组日志文件被写满 ...
- 怎样下载linux的日志文件,Linux常见的日志文件及查看命令
Linux常见日志和常用命令 Linux 日志都以明文形式存储,所以我们不需要特殊的工具就可以搜索和阅读它们.Linux 日志存储在 /var/log 目录中,我们可以编写脚本,来扫描这些日志,并基于 ...
- java如何读取自定义log4j2_spring boot自定义log4j2日志文件的实例讲解
背景:因为从 spring boot 1.4开始的版本就要用log4j2了,支持的格式有json和xml两种格式,此次实践主要使用的是xml的格式定义日志说明. spring boot 1.5.8.R ...
- 所属文件不可访问_日志文件写入失败(permission denied)
用过Laravel的小伙伴一开始安装完框架后可能都遇到过daily 日志文件写入失败的问题,接下来我们就来详细说下日志文件写入失败的原因以及对应的解决方案. 在讲这个问题之前可能需要简单介绍下Linu ...
- oracle 安装时的日志文件,oracle10g安装的日志文件 Oracle10g怎么查看操作日志
如何查看oracle 10g 的操作日志 归档模式下怎么查询oracle 10g归档日志存放的路径? SQL> select name from v$archived_log; NAME /u0 ...
- 数据库服务器备份日志文件,数据库服务器备份日志文件
数据库服务器备份日志文件 内容精选 换一换 使用自定义脚本实现数据库备份完成后,可以通过如下操作验证数据库备份结果是否成功.本章节以SQL_SERVER数据库为例进行验证. 业界对备份一致性的定义包括 ...
- 服务器查看数据库日志文件,服务器数据库查看日志文件
服务器数据库查看日志文件 内容精选 换一换 对于不同业务场景,通过在调整数据库的参数配置,可以有效提升服务器性能.使用如下配置文件参数启动数据库,默认配置文件路径为/etc/my.cnf, 其中MyS ...
- mysql日志文件名字_MySQL各类日志文件相关变量介绍
文章转自:http://www.ywnds.com/?p=3721 查询所有日志的变量 1 mysql>show global variables like'%log%'; GLOBAL表示查全 ...
- linux日志文件存放目录,Log4j 日志文件Linux/Mac/Windows通用存放位置设置方法
log4j1/log4j2中category的配置以及log的输出位置(windows和linux通用的log输出位置) 一.场景和需求 假设我现在有3个独立的用project(暂时用maven关联起 ...
最新文章
- 【ACM】杭电OJ 2040
- python装keras_python – 在anaconda中安装keras时出错. / p KER...
- java温度计的实现_echart 之实现温度计
- 未来5年,中国会有多少企业营收能达到1000亿美元以上?
- 计算机软件复用意义何在,2009计算机科学技术导论复习要点.pdf
- C语言从来都没有过时,你大爷终究是你大爷
- 《学C编程也可以卡通一点》一1.7变量的类型
- exc导入mysql phpcms_PHP如何将EXCEL导入MYSQL,急!!!急!!哪位大师能帮帮忙啊,给个详细代码...
- Acrobat Pro DC 2022 Mac(全能PDF工具)完美兼容m1
- svn合并分支到主干
- 8.声卡驱动02-自己实现alsa驱动-虚拟声卡-匹配
- 【Linux】Infiniband 驱动安装---(HCA光钎)---mlnx
- react-native 轮播组件 looped-carousel使用介绍
- 博客做外链不收录怎么办,如何利用博客做外链
- rabbitMQ队列解绑
- 垂直投影法分割验证码
- 屏幕坐标系转为笛卡尔坐标系
- 做中国强制性CCC认证需要多少钱
- Android中使用logger打印完整的okhttp网络请求和响应的所有相关信息(请求行、请求头、请求体、响应行、响应行、响应头、响应体)
- You do not have sufficient permissions to access the inventory ‘/u01/app/oraInventory‘.
热门文章
- zabbix4监控mysql_Zabbix4监控Mysql5.7
- 168输出为861java_AcWing 861. 二分图的最大匹配-java-关键处注释
- java mysql 动态sql_Java下拼接运行动态SQL语句
- 威客php,phpapp威客系统下载
- sails mysql_sails项目创建与常用基础操作总结
- Python数据分析学习笔记:Python数据可视化入门
- 【BZOJ3050】Seating,线段树
- 【codevs4654】【BZOJ2442】修剪草坪,第一次的单调队列,优化DP
- 9.霍夫变换:圆——圆的算法、投票使用技巧、优点和缺点_2
- 如何维持手机电池寿命_手机电池不耐用,都怪这些充电坏毛病