【.Net】 大文件可使用的文本分组统计工具(附带源码,原创)
本工具可实现的效果:
1.读取大文件(大于1GB)
2.根据分隔符分割后的列分组
3.速度快。
4.处理过程中,可以随时停止处理,操作不卡死。
5.有对当前内存的实时监测,避免过多占用内存,影响系统运行。
6.实时显示处理的行数。
处理类代码:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text; namespace DaZhongLogTool
{ // 定义事件的参数类
public class ValueEventArgs : EventArgs
{
public int Value { set; get; }
}
// 定义事件使用的委托
public delegate void ValueChangedEnentHandler(object sender, ValueEventArgs e); public class BigFileTongJiJobs
{
long ALLOW_MAX_USED_MEMORY = 1024 * 1024 * 1024; //允许使用的最大内存,超过则结束 public bool StartFlag { get; set; } // 定义一个事件来提示界面工作的进度
public event ValueChangedEnentHandler ValueChanged; public void OnValueChange(ValueEventArgs e)
{
if (ValueChanged != null)
{
ValueChanged(this, e);
}
} /// <summary>
///
/// </summary>
/// <param name="paramsInfo"></param>
/// <returns>-1:未开始,就失败了;-2:文件不存在;-3,异常;大于0,处理成功</returns>
public int StartAnalyseBigFile(TongjiParamsInfoStruct paramsInfo)
{
int handleLine = -1; string sTmpFile = paramsInfo.outputPath;
if (File.Exists(sTmpFile))
{
File.Delete(sTmpFile);
} if (!System.IO.File.Exists(sTmpFile))
{
FileStream fs;
fs = File.Create(sTmpFile);
fs.Close();
} if (!File.Exists(paramsInfo.inputPath))
{
handleLine = -2;
return handleLine;
} FileStream streamInput = System.IO.File.OpenRead(paramsInfo.inputPath);
FileStream streamOutput = System.IO.File.OpenWrite(sTmpFile); int iRowCount = 0;
int iRowCharCount = 0;
List<byte> rowByteData = new List<byte>();//行字节List
Dictionary<string, int> tongjiDict = new Dictionary<string, int>(); //统计字典
string rowStr = ""; //获取当前进程对象
Process cur = Process.GetCurrentProcess();
//为获取当前进程使用的内存大小做准备
PerformanceCounter curpc = new PerformanceCounter("Process", "Working Set", cur.ProcessName);
string memoryUsedSize = "";
try
{
ValueEventArgs e;
int result; //根据当前进程使用内存的大小,决定是否继续分析日志文本
memoryUsedSize = string.Format("分析开始,本进程使用内存大小:{0} KB,Date:{1}", curpc.NextValue() / 1024, DateTime.Now);
streamOutput.Write(System.Text.UTF8Encoding.UTF8.GetBytes(memoryUsedSize), 0, System.Text.UTF8Encoding.UTF8.GetBytes(memoryUsedSize).Length);
streamOutput.WriteByte(13); //换行符 while ((result = streamInput.ReadByte()) != -1)
{ if (StartFlag == false)
{
streamOutput.Write(System.Text.UTF8Encoding.UTF8.GetBytes("强制停止分析"), 0, System.Text.UTF8Encoding.UTF8.GetBytes("强制停止分析").Length);
streamOutput.WriteByte(13);
break;
} if (result == 10)
continue;
iRowCharCount++;
rowByteData.Add((byte)result);
if (result == 13) //一行
{ //写入一次或者处理一次
rowStr = GetSpecificInfoFromLineText(rowByteData, paramsInfo.separator, paramsInfo.columnNum);
if (!string.IsNullOrEmpty(rowStr))
{
rowStr = rowStr.Length > 300 ? rowStr.Substring(0, 300) : rowStr;
if (tongjiDict.ContainsKey(rowStr))
tongjiDict[rowStr] = tongjiDict[rowStr] + 1;
else
tongjiDict[rowStr] = 1;
} if (iRowCount % 10000 == 0 || iRowCount<100) //不频繁的更新UI可以极大的提高处理的效率,如果每条都更新UI,将会非常慢
{
//占用内存大于1GB,则结束本次的分析
if (curpc.NextValue() > ALLOW_MAX_USED_MEMORY)//当前进程使用内存的大小大于1个GB,停止分析
{
break;
} e = new ValueEventArgs() { Value = iRowCount };
this.OnValueChange(e);
} iRowCount++; //统计处理的行数
iRowCharCount = 0;//本行的字符数
rowByteData.Clear();//清空本行数据
}
} if (tongjiDict.Count> 1)
{
//根据当前进程使用内存的大小,决定是否继续分析日志文本
memoryUsedSize = string.Format("分析结束:本进程使用内存大小:{0} KB,Date:{1},分组个数:{2}", curpc.NextValue() / 1024, DateTime.Now,tongjiDict.Count);
streamOutput.Write(System.Text.UTF8Encoding.UTF8.GetBytes(memoryUsedSize), 0, System.Text.UTF8Encoding.UTF8.GetBytes(memoryUsedSize).Length);
streamOutput.WriteByte(13); //换行符
} streamOutput.Write(System.Text.UTF8Encoding.UTF8.GetBytes("本次处理的文本对象是"), 0, System.Text.UTF8Encoding.UTF8.GetBytes("本次处理的文本对象是").Length);
streamOutput.Write(System.Text.UTF8Encoding.UTF8.GetBytes(paramsInfo.inputPath), 0, System.Text.UTF8Encoding.UTF8.GetBytes(paramsInfo.inputPath).Length);
streamOutput.WriteByte(13); string temLine;
foreach (var item in tongjiDict.OrderByDescending(t => t.Value))
{
temLine = string.Format("统计次数Value:{0}\t Key: {1}", item.Value, item.Key);
streamOutput.Write(System.Text.UTF8Encoding.UTF8.GetBytes(temLine), 0, System.Text.UTF8Encoding.UTF8.GetBytes(temLine).Length);
streamOutput.WriteByte(13); //换行符
}
//更新处理到最后一条的文字提示状态
e = new ValueEventArgs() { Value = iRowCount };
this.OnValueChange(e);
}
finally
{
streamInput.Dispose();
streamOutput.Dispose();
} return iRowCount;
} //从文本行中提取特定信息
private string GetSpecificInfoFromLineText(List<byte> lineArr, string separator, int columnNum)
{
string result;
try
{
string lineStr;
string[] columnArr;
lineStr = System.Text.UTF8Encoding.UTF8.GetString(lineArr.ToArray());
//把文本中的 "\t",替换为分隔符 "\\t",原因是:输入的分隔符是:“\t”,为了避免被转移,系统自动把输入的分隔符变成了:“\\t”
//去掉\r后面或者前面的\n,避免输出的文本中根据\n换行
columnArr = lineStr.Replace("\t", "\\t").Replace('\n', ' ').Split(new string[] { separator }, StringSplitOptions.None);
if (columnArr.Length < columnNum)
{
return "";
}
result = columnArr[columnNum - 1];
}
catch (Exception)
{
result = "ExceptionLine";
//throw;
}
return result;
} } public struct TongjiParamsInfoStruct
{
public string inputPath { get; set; }
public string outputPath { get; set; }
public string separator { get; set; }
public int columnNum { get; set; } }
}
调用代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms; namespace DaZhongLogTool
{
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
} Color originalTongJiButtonColor;
string originalTongJiButtonText; BigFileTongJiJobs tongjiJobs = new BigFileTongJiJobs(); private void btnTongJi_Click(object sender, EventArgs e)
{
if (tongjiJobs.StartFlag)
{
MessageBox.Show("正在处理中...,如需停止,请单击停止");
return;
} string errmsg;
if(string.IsNullOrEmpty(txtSeparator.Text))
{
MessageBox.Show("请输入分隔符");
return;
}
if (numericUpDown1.Value<1)
{
MessageBox.Show("请输入按照分隔符分割的待统计内容的对应的列数,从1开始");
return;
} string inputPath = txtInputPath.Text.Trim();
if (string.IsNullOrEmpty(inputPath))
{
MessageBox.Show("请输入等待统计的文本路径");
return;
}
if(!File.Exists(inputPath))
{
MessageBox.Show("待统计的文本文件不存在,请重新输入");
return;
} TongjiParamsInfoStruct paramsInfo = new TongjiParamsInfoStruct();
paramsInfo.inputPath = inputPath;
paramsInfo.outputPath = System.IO.Path.GetDirectoryName(inputPath)+@"\"+DateTime.Now.ToString("yyyyMMdd_HHmm")+"_result.log";
paramsInfo.separator = txtSeparator.Text;
paramsInfo.columnNum = (int)numericUpDown1.Value; originalTongJiButtonColor = this.btnTongJi.BackColor;
originalTongJiButtonText = this.btnTongJi.Text; ////开始分析前,改变按钮颜色及文字
//this.btnTongJi.Enabled = false;
//this.btnTongJi.BackColor = Color.Gray;
//this.btnTongJi.Text = "处理中……"; tongjiJobs.StartFlag = true;
tongjiJobs.ValueChanged += new ValueChangedEnentHandler(Line_ValueChange); Func<TongjiParamsInfoStruct, int> hander = new Func<TongjiParamsInfoStruct, int>(tongjiJobs.StartAnalyseBigFile);
hander.BeginInvoke(paramsInfo, new AsyncCallback(AsyncCallback1), hander); } // 结束异步操作
private void AsyncCallback1(IAsyncResult ar)
{
// 标准的处理步骤
Func<TongjiParamsInfoStruct, int> handler = ar.AsyncState as Func<TongjiParamsInfoStruct, int>;
int result= handler.EndInvoke(ar); if (result>0)
{
MessageBox.Show("本次成功处理了" + result + "行数据", "成功");
}
else if (result == -2)
{
MessageBox.Show("文件不存在,请重新选择");
}
toolStripStatusLabel1.Text = "上次任务处理完毕,等待下次开始。" + DateTime.Now.ToString(); tongjiJobs.StartFlag = false;//处理过程停止 //恢复按钮颜色及文字
//this.btnTongJi.Enabled = true;
//this.btnTongJi.BackColor = originalTongJiButtonColor;
//this.btnTongJi.Text = originalTongJiButtonText; } private void Line_ValueChange(object sender ,ValueEventArgs e)
{
toolStripStatusLabel1.Text = string.Format("统计中……,已处理了{0}行日志,时间:{1}", e.Value, DateTime.Now);
} private void btnSelectFile_Click(object sender, EventArgs e)
{
OpenFileDialog fileDialog = new OpenFileDialog();
fileDialog.Multiselect = false;
fileDialog.Filter = "(*.*)|*.*";
fileDialog.RestoreDirectory = false; if (fileDialog.ShowDialog() == DialogResult.OK)
{
try
{
txtInputPath.Text=fileDialog.FileName;
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
} private void btnStopTongJi_Click(object sender, EventArgs e)
{
//点击停止按钮
tongjiJobs.StartFlag = false;
} } }
该工具,是来自于实际工作的需求,用于根据某一列统计次数。简单实用。
源代码下载:【源码】大文件分组统计简单工具 【EXE】大文件分组统计简单工具
需要的小伙伴尽管拿走,不要忘记推荐一下,谢谢
【.Net】 大文件可使用的文本分组统计工具(附带源码,原创)的更多相关文章
- 一篇文章看懂TPCx-BB(大数据基准测试工具)源码
TPCx-BB是大数据基准测试工具,它通过模拟零售商的30个应用场景,执行30个查询来衡量基于Hadoop的大数据系统的包括硬件和软件的性能.其中一些场景还用到了机器学习算法(聚类.线性回归等).为了 ...
- 鸿蒙内核源码分析(文件句柄篇) | 深挖应用操作文件的细节 | 百篇博客分析OpenHarmony源码 | v69.01
百篇博客系列篇.本篇为: v69.xx 鸿蒙内核源码分析(文件句柄篇) | 深挖应用操作文件的细节 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说 ...
- java 导出 excel 最佳实践,java 大文件 excel 避免OOM(内存溢出) excel 工具框架
产品需求 产品经理需要导出一个页面的所有的信息到 EXCEL 文件. 需求分析 对于 excel 导出,是一个很常见的需求. 最常见的解决方案就是使用 poi 直接同步导出一个 excel 文件. 客 ...
- arcgis api 3.x for js 解决 textSymbol 文本换行显示(附源码下载)
前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...
- 鸿蒙内核源码分析(源码结构篇) | 内核每个文件的含义 | 百篇博客分析OpenHarmony源码 | v18.04
百篇博客系列篇.本篇为: v18.xx 鸿蒙内核源码分析(源码结构篇) | 内核每个文件的含义 | 51.c.h .o 前因后果相关篇为: v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 ...
- iOS富文本组件的实现—DTCoreText源码解析 数据篇
本文转载 http://blog.cnbang.net/tech/2630/ DTCoreText是个开源的iOS富文本组件,它可以解析HTML与CSS最终用CoreText绘制出来,通常用于在一些需 ...
- 分享一个文件查找、替换制定的字符或数字之CS程序、附带源码
首先就上操作流程图: 图--登陆界面.登陆密码:alidoing.com 图--界面说明(一看就懂) 图--文件查找到再替换 图--文件替换成功 图--替换后的文件 代码开始: 登陆的代码就非常简单. ...
- 图解DevExpress RichEditControl富文本的使用,附源码及官方API
9点半了,刚写到1.2. 该回家了,明天继续写完. 大家还需要什么操作,留言说一下,没有的我明天继续加. 好久没有玩DevExpress了,今天下载了一个玩玩,发现竟然更新到14.2.5了..我去 ...
- Python对文本读写的操作方法【源码】
Dear ALL 今天给大家分享的是 TXT文本读写方式,也是文件操作最常用的一种方式,主要内容有: 文件写方法 文件读方法 with open() as f 方法 话不多说,码上见: ''' 标题: ...
随机推荐
- 第二章 C#语法基础 (2.2 C#语言的运算符和表达式)
[案例]本案例通过随机数发生器随机产生三条边,要求输出三天边长(边长长度为1~20的整数),并判断是否可以构成一个三角形. 如果可以,则计算出三角形面积,否则输出信息”三条随机的边不能构成三角形“. ...
- asp.net:mv4 FileResult在IE8中下载不显示文件名和扩展名而显示Action方法名了!
IE8下,用户点击下载文件,会发现文件类型失丢的问题,解决方案如下: //IE8下载时,只显示action的名字,没有文件名和后缀 @仰止网Simba //return File(bufferbyte ...
- MIDAS.dll 出错时 (Error loading MIDAS.DLL.)
DELPHI 写的程序会出 ---------------------------Pmain---------------------------Error loading MIDAS.DLL.--- ...
- 给idea添加类注释和方法注释模板
这是我找到的最好的,最简单明白的一文: https://blog.csdn.net/xiaoliulang0324/article/details/79030752
- WampServer的下载方法
http://www.wampserver.com/ 无法访问 报网络连接错误 2019.01.13 最近要用到Windows+apache+mysql+php,为了追求更快的实现速度和更高的稳定性, ...
- vscode, cmake编译多个C++文件
目的是利用vscode及相关插件编译多个C++文件. 我已经装好cmake和mingw并且将它们的路径添加到系统变量path中了. vscode装上如下几个插件: 点击vscode左上角 文件-& ...
- [UE4]Menu Anchor,菜单锚点
一.想要弹出某个菜单的时候,Menu Anchor可以做为菜单弹出的位置. 二.Menu Anchor本身不显示任何东西 三.Menu Class:选择要弹出的UI,可以是任意的UserWidget ...
- 冷知识点:COLLATE 关键字是什么意思?
mysql 数据库表: CREATE TABLE `book_order_test` ( `order_id` varchar(50) COLLATE utf8_bin DEFAULT NULL CO ...
- HTML5 使用小结
1.html5新增的常用元素 (a) <article.../>代表独立完整的一遍文章 (b)<section.../>对页面内容进行分块 (c)<nav.../> ...
- 实验五:Xen环境下多虚拟机的桥接配置
实验名称: Xen环境下多虚拟机的桥接配置 实验环境: 这里我们首先需要有一台已经安装好的虚拟机机,能够正常运行,且网卡正常,如下图: 实验需求: 进行虚拟机的复制,并添加新的网桥配置,然后将两台虚拟 ...