一种快速生成CSV的方法

2024-09-08 07:28
文章标签 方法 快速 生成 csv 一种

本文主要是介绍一种快速生成CSV的方法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

事情是这个样子的

在QQ群在聊把如何100万数据导出成CSV文件?会不会很慢?

俺回了一句“现在的机器性能好,没啥问题”。

然后大家开始谈论机器的配置了。哎,俺的机器配置有点差。

然后俺就进行了一个测试。

测试数据

数据定义

        public struct Rec
        {
            public int v1;
            public int v2;
        }
        private Rec[] Data;

        这里为啥不用class呢,因为这个场景struct 更简单。

测试数据生成

            Data = new Rec[200*10000];
            Random r = new Random(DateTime.Now.Millisecond);
            for(int i= 0;i < Data.Length;i++)
            {
                Data[i].v1 = r.Next();
                Data[i].v2 = r.Next();
            }

测试数据200万行,每行2个数字。

测试结果

测试程序为 .NET Framework 4.8 64 Release 版本

如果用.Net 8 版本进行测试,除了方法3之外,会快一些。方法3速度基本不变。

 开始写代码

方法一

这是最最普通的生成CSV的方法,就是一个一个数据的写入到CSV中。没啥可说的。就是用来当做参照物的,耗时0.536秒

            string fn = @"1.csv";  FileStream fs = new FileStream(fn, FileMode.Create);DateTime t1 = DateTime.Now;byte[] buff;byte[] buff_rn = ASCIIEncoding.ASCII.GetBytes("\r\n");byte[] buff_split = ASCIIEncoding.ASCII.GetBytes(",");string s ="v1,v2";buff = ASCIIEncoding.ASCII.GetBytes(s);fs.Write(buff,0,buff.Length);foreach (Rec i in Data){fs.Write(buff_rn, 0, buff_rn.Length); s = i.v1.ToString();buff = ASCIIEncoding.ASCII.GetBytes(s);fs.Write(buff, 0, buff.Length);fs.Write(buff_split, 0, buff_split.Length);s = i.v2.ToString();buff = ASCIIEncoding.ASCII.GetBytes(s);fs.Write(buff, 0, buff.Length);  }fs.Flush();fs.Close();fs.Dispose();DateTime t2 = DateTime.Now;label1.Text=("输出"+Data.Length.ToString()+"行CSV文件,耗时" +((t2 - t1).TotalMilliseconds/1000).ToString("0.000")+"秒");

方法二

在方法1上加了一个8M的缓存。其实这种写法在其他语言(c++、delphi 等)还有效果,C#效果不大,因为C#的文件流本身有优惠。耗时0.503秒

            string fn = @"2.csv"; int ms_size = 8 * 1024 * 1024;byte[] ms=new byte[ms_size + 1024];int ms_position = 0;FileStream fs = new FileStream(fn, FileMode.Create);DateTime t1 = DateTime.Now;byte[] buff;byte[] buff_rn = ASCIIEncoding.ASCII.GetBytes("\r\n");byte[] buff_split = ASCIIEncoding.ASCII.GetBytes(",");string s = "v1,v2";buff = ASCIIEncoding.ASCII.GetBytes(s);Array.Copy(buff, 0, ms, ms_position, buff.Length);ms_position+= buff.Length;foreach (Rec i in Data){Array.Copy(buff_rn, 0, ms, ms_position, buff_rn.Length);ms_position += buff_rn.Length; s = i.v1.ToString();buff = ASCIIEncoding.ASCII.GetBytes(s); Array.Copy(buff, 0, ms, ms_position, buff.Length);ms_position += buff.Length;Array.Copy(buff_split, 0, ms, ms_position, buff_split.Length);ms_position += buff_split.Length;s = i.v2.ToString();buff = ASCIIEncoding.ASCII.GetBytes(s);Array.Copy(buff, 0, ms, ms_position, buff.Length);ms_position += buff.Length;if (ms_position > ms_size){ fs.Write(ms,0, ms_position); ms_position = 0;}}if (ms_position > 0){fs.Write(ms, 0, ms_position);}fs.Flush();fs.Close();fs.Dispose();DateTime t2 = DateTime.Now;label2.Text = ("输出" + Data.Length.ToString() + "行CSV文件,耗时" + ((t2 - t1).TotalMilliseconds / 1000).ToString("0.000") + "秒");

优化

我们先分析一下,生成CSV中,主要的计算是啥?在这个测试上主要计算就是,整型转字符串。执行了400万次(200万行,每行2个数字)整型转字符串。那么我们就先测试一下执行了400万次整型转字符串多少时间。

            string s = "";DateTime t1 = DateTime.Now;foreach (Rec i in Data){s = i.v1.ToString();s = i.v2.ToString();}DateTime t2 = DateTime.Now;label4.Text = ( (Data.Length*2).ToString() + "次ToString,耗时" + ((t2 - t1).TotalMilliseconds / 1000).ToString("0.000") + "秒");

耗时是0.265秒

那么我们就像从 整型转字符串 开始优化。

方法三

  使用了 IntToString 函数,速度优化到了 耗时0.176秒。优化到这里出现了一个有趣的数据:

 只执行 整型转字符串 耗时是0.265秒,方法三的速度比只 整型转字符串 还快。为什么呢?

因为在 方法三 中,其实没有使用字符串,取消中间商赚差价。

           string fn = @"3.csv";int ms_size = 8 * 1024 * 1024;byte[] ms = new byte[ms_size + 1024];int ms_position = 0;FileStream fs = new FileStream(fn, FileMode.Create);DateTime t1 = DateTime.Now;byte[] buff;byte[] buff_rn = ASCIIEncoding.ASCII.GetBytes("\r\n");byte[] buff_split = ASCIIEncoding.ASCII.GetBytes(",");string s = "v1,v2";buff = ASCIIEncoding.ASCII.GetBytes(s);Array.Copy(buff, 0, ms, ms_position, buff.Length);ms_position += buff.Length;foreach (Rec i in Data){Array.Copy(buff_rn, 0, ms, ms_position, buff_rn.Length);ms_position += buff_rn.Length;IntToString(i.v1,ref ms, ref ms_position); Array.Copy(buff_split, 0, ms, ms_position, buff_split.Length);ms_position += buff_split.Length;IntToString(i.v2, ref ms, ref ms_position);if (ms_position > ms_size){fs.Write(ms, 0, ms_position);ms_position = 0;}}if (ms_position > 0){fs.Write(ms, 0, ms_position);}fs.Flush();fs.Close();fs.Dispose();DateTime t2 = DateTime.Now;label3.Text = ("输出" + Data.Length.ToString() + "行CSV文件,耗时" + ((t2 - t1).TotalMilliseconds / 1000).ToString("0.000") + "秒");

这个代码的功能  其实就个 int.ToString。 看上去下面这个代码有点拉胯,像是那种故意搞笑的代码,是的确实拉胯,但是它确实快。

        public static void IntToString(int n,ref byte[] buff,ref int position){int len = 0;int len_inc = 16;int p = position+ len_inc;do{buff[p] = (byte)((n % 10)+48);p += 1;len += 1;}while ((n /= 10) != 0);p -= 1;for (int i = 0; i < len;i++){buff[position]= buff[p];position += 1;p -= 1;} }

其他

Release 版本 和 Debug版本差别很大,例如 方法三 的Debug版 速度并不快,但是用Release 版本,方法3就明显快。

使用.Net 8 版本进行测试,结果如下

.NET Framework 4.8.Net 8对比
方法10.5380.257.Net 8 快很多
方法20.5030.190.Net 8 快很多
方法30.1760.178两者差不多
整型转字符串0.2650.075.Net 8 快很多

上面的数据进行时测试,不是很准确。但是可以看出 :

.Net 8 在 整型转字符串 上要快很多。方法三因为没有用 .ToString() 所以 速度在.NET Framework 4.8  和  .Net 8 下差不多。

这篇关于一种快速生成CSV的方法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1147491

相关文章

AI一键生成 PPT

AI一键生成 PPT 操作步骤 作为一名打工人,是不是经常需要制作各种PPT来分享我的生活和想法。但是,你们知道,有时候灵感来了,时间却不够用了!😩直到我发现了Kimi AI——一个能够自动生成PPT的神奇助手!🌟 什么是Kimi? 一款月之暗面科技有限公司开发的AI办公工具,帮助用户快速生成高质量的演示文稿。 无论你是职场人士、学生还是教师,Kimi都能够为你的办公文

电脑桌面文件删除了怎么找回来?别急,快速恢复攻略在此

在日常使用电脑的过程中,我们经常会遇到这样的情况:一不小心,桌面上的某个重要文件被删除了。这时,大多数人可能会感到惊慌失措,不知所措。 其实,不必过于担心,因为有很多方法可以帮助我们找回被删除的桌面文件。下面,就让我们一起来了解一下这些恢复桌面文件的方法吧。 一、使用撤销操作 如果我们刚刚删除了桌面上的文件,并且还没有进行其他操作,那么可以尝试使用撤销操作来恢复文件。在键盘上同时按下“C

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

浅谈主机加固,六种有效的主机加固方法

在数字化时代,数据的价值不言而喻,但随之而来的安全威胁也日益严峻。从勒索病毒到内部泄露,企业的数据安全面临着前所未有的挑战。为了应对这些挑战,一种全新的主机加固解决方案应运而生。 MCK主机加固解决方案,采用先进的安全容器中间件技术,构建起一套内核级的纵深立体防护体系。这一体系突破了传统安全防护的局限,即使在管理员权限被恶意利用的情况下,也能确保服务器的安全稳定运行。 普适主机加固措施:

webm怎么转换成mp4?这几种方法超多人在用!

webm怎么转换成mp4?WebM作为一种新兴的视频编码格式,近年来逐渐进入大众视野,其背后承载着诸多优势,但同时也伴随着不容忽视的局限性,首要挑战在于其兼容性边界,尽管WebM已广泛适应于众多网站与软件平台,但在特定应用环境或老旧设备上,其兼容难题依旧凸显,为用户体验带来不便,再者,WebM格式的非普适性也体现在编辑流程上,由于它并非行业内的通用标准,编辑过程中可能会遭遇格式不兼容的障碍,导致操

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

poj 1287 Networking(prim or kruscal最小生成树)

题意给你点与点间距离,求最小生成树。 注意点是,两点之间可能有不同的路,输入的时候选择最小的,和之前有道最短路WA的题目类似。 prim代码: #include<stdio.h>const int MaxN = 51;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int P;int prim(){bool vis[MaxN];

poj 2349 Arctic Network uva 10369(prim or kruscal最小生成树)

题目很麻烦,因为不熟悉最小生成树的算法调试了好久。 感觉网上的题目解释都没说得很清楚,不适合新手。自己写一个。 题意:给你点的坐标,然后两点间可以有两种方式来通信:第一种是卫星通信,第二种是无线电通信。 卫星通信:任何两个有卫星频道的点间都可以直接建立连接,与点间的距离无关; 无线电通信:两个点之间的距离不能超过D,无线电收发器的功率越大,D越大,越昂贵。 计算无线电收发器D

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验