C# 使用LINQ查询巨大的CSV和Excel
我试图找到方法来访问巨大的Excel或CSV文件,并执行聚合操作,如求和、计数和某些类似SQL的操作,如选择、分组等。 我知道LINQ可以帮我做到这一点。我更喜欢使用C。我的问题是: 1执行任何查询时,excel或CSV中的数据是否会加载到内存中?所有文件都在12GB左右。我问的原因是我不希望应用程序挂起 2我可以创建一个表单应用程序,其中我有一个文本区域,列出CSV/Excel的所有列。用户可以选择文本区域中的任何列。我计划使用SQL选项,如选择、分组、求和、平均值和许多其他选项。用户可以选择其中的一个,然后在内部使用LINQ构建查询并获得结果。结果可以存储在文本文件中 我不确定这是否可行。请就此向我提出建议。我不熟悉使用LINQ。 如果无法通过LINQ实现这一点,请您建议其他有效的方法C# 使用LINQ查询巨大的CSV和Excel,c#,sql,excel,linq,csv,C#,Sql,Excel,Linq,Csv,我试图找到方法来访问巨大的Excel或CSV文件,并执行聚合操作,如求和、计数和某些类似SQL的操作,如选择、分组等。 我知道LINQ可以帮我做到这一点。我更喜欢使用C。我的问题是: 1执行任何查询时,excel或CSV中的数据是否会加载到内存中?所有文件都在12GB左右。我问的原因是我不希望应用程序挂起 2我可以创建一个表单应用程序,其中我有一个文本区域,列出CSV/Excel的所有列。用户可以选择文本区域中的任何列。我计划使用SQL选项,如选择、分组、求和、平均值和许多其他选项。用户可以选择
提前感谢。内存不是你的问题,性能是你的问题 我完全同意关于将其加载到适当的数据库中的意见,该数据库将索引行等,以使其更高效。尽管如此,如果直接读取CSV是非常不可取的,那么执行您描述的各种查询是可能的和直接的 我认为在这个任务中测试会很有趣 由于没有任何现成的大型csv文件,我只生成了一个具有以下标题的文件:
"row,Guid,Grouping1,Grouping2,Metric1,Metric2"
其中row是行号,Guid只是一个随机Guid Grouping1是一个介于0和49之间的随机整数,Grouping2是介于0和50000之间的随机整数,Metric1和Metric2分别是随机整数和双精度整数。基本上只是一些随机数据
然后我生成了一个包含9999999行的7Gb+文件…我的目标是100000000行,但在某个地方遇到了我的零索引盲点
好消息是LINQtoCSV将很高兴地解析这个坏小子,而不必将文件加载到内存中。只需在csv中创建一行表示的类:
class Entry
{
[CsvColumn(FieldIndex = 1, Name="row")]
public long Id { get; set; }
[CsvColumn(FieldIndex = 2)]
public string Guid { get; set; }
[CsvColumn(FieldIndex = 3)]
public int Grouping1 { get; set; }
[CsvColumn(FieldIndex = 4)]
public int Grouping2 { get; set; }
[CsvColumn(FieldIndex = 5)]
public int Metric1 { get; set; }
[CsvColumn(FieldIndex = 6)]
public double Metric2 { get; set; }
}
然后将条目读入IEnumerable:
查询该文件大约需要25分钟。如果这不能使您将其放入一个正确索引的数据库中,那么什么都不会 您是否尝试过,但失败了?excel文件是真正的excel文件还是扩展名为.xls/.xlsx的text/csv文件?答案:1这取决于您将编写的查询。如果你擅长编程,你可以,否则你就不行。请认真阅读,以了解如何在堆栈溢出问题上提问。可能需要考虑将文件加载到DB中,因为它是为查询而设计的。
IEnumerable<Entry> ReadEntries()
{
CsvFileDescription inputFileDescription = new CsvFileDescription
{
SeparatorChar = ',',
FirstLineHasColumnNames = true
};
CsvContext ctx = new CsvContext();
return ctx.Read<Entry>("test.csv", inputFileDescription);
}
static IEnumerable<Entry> entries;
static void Main(string[] args)
{
entries = ReadEntries();
var tasks = new List<Task> {timeEntryCount,timeEntryCountWhereG1_equals_1,timeMetric2SumWhereG2_equals_1};
tasks.ForEach(t => t.Start());
Task.WaitAll(tasks.ToArray());
Console.WriteLine("Entry count took " + timeEntryCount.Result);
Console.WriteLine("Entry count where G1==1 took " + timeEntryCountWhereG1_equals_1.Result);
Console.WriteLine("Metric1 sum where G2==1 took " + timeMetric2SumWhereG2_equals_1.Result);
Console.ReadLine();
}
static Task<TimeSpan> timeMetric2SumWhereG2_equals_1 = new Task<TimeSpan>(() =>
{
DateTime start = DateTime.Now;
double sum = entries
.Where(e => e.Grouping2 == 1)
.Sum(e=>e.Metric2);
Console.WriteLine("sum: " + sum);
DateTime end = DateTime.Now;
return end - start;
},TaskCreationOptions.LongRunning);
static Task<TimeSpan> timeEntryCountWhereG1_equals_1 = new Task<TimeSpan>(() =>
{
DateTime start = DateTime.Now;
long count = entries
.Where(e=>e.Grouping1==1)
.Count();
DateTime end = DateTime.Now;
Console.WriteLine("countG1: " + count);
return end - start;
}, TaskCreationOptions.LongRunning);
static Task<TimeSpan> timeEntryCount = new Task<TimeSpan>(() =>
{
DateTime start = DateTime.Now;
long count = entries.Count();
Console.WriteLine("CountAll: " + count);
DateTime end = DateTime.Now;
return end - start;
}, TaskCreationOptions.LongRunning);
countG1: 2003023
CountAll: 99999999
sum: 1236810295.16543
Entry count took 00:25:26.3767852
Entry count where G1==1 took 00:24:41.9855814
Metric1 sum where G2==1 took 00:25:30.9080960