将LINQ结果写入文本文件

时间:2014-10-18 16:49:59

标签: c# linq

我正在尝试将LINQ查询的输出写入文本文件。为此,我使用的是扩展方法。

这是我的LINQ查询:

var group =
    from c in census_data
    group c by c.state into g
    join s in state_gdp on g.FirstOrDefault().state equals s.state
    orderby s.gdp descending
    select new
    {
        State = g.Key,
        Count = g.Count(),
        SavingsBalance = g.Average(x => x.savingsBalanceDouble),
        GDP = s.gdp
    };

这是我的扩展方法:

public static class CSVWriter
{
    public static void write(this Enumerable e, string file)
    {
        using (System.IO.StreamWriter f = new System.IO.StreamWriter(file))
        {
            foreach (var i in e)
            {
                f.WriteLine(i);
            }
        }
    }
}

但是我收到一条错误消息,指出System.Linq.Enumerable没有getEnumerator方法。

1 个答案:

答案 0 :(得分:1)

可能的解决方案如下所示:

var result =
    from c in census_data
    group c by c.state into g
    join s in state_gdp on g.FirstOrDefault().state equals s.state
    orderby s.gdp descending
    select new
    {
        State = g.Key,
        Count = g.Count(),
        SavingsBalance = g.Average(x => x.savingsBalanceDouble),
        GDP = s.gdp
    };

var buffer = new StringBuilder();
buffer.AppendLine("#key,name,sum,gdp");
result.ToList().ForEach(item => buffer.AppendLine(String.Format("{0},{1},{2},{3}", item.State, item.Count, item.SavingBalance, item.GDP)));
File.WriteAllText("d:\\temp\\file.csv", buffer.ToString());

您需要将Enumerable更改为IEnumerable。由于您正在创建匿名对象,因此您的解决方案会将匿名对象列表(IEnumerable<anonymous>)传输到您将数据写入文件的函数,但您将无法根据需要格式化输出。

一种可能的解决方案是将要写入文件的行放入字符串缓冲区,然后使用System.IO.File.WriteAllText方法立即写入文本:

// test data
var data = new List<Int32> { 1, 20, 30, 40, 50, 70 };
// create a list of anonymous objects
var result = data.Select (d => new 
{
    Count = d,
    State = String.Format("Item {0}", d),
    SavingBalance = d * 10
});
// create the output text buffer
var buffer = new StringBuilder();
// add header line
buffer.AppendLine("#key,name,sum");
// add each result line
result.ToList().ForEach(item => buffer.AppendLine(String.Format("{0},{1},{2}", item.Count, item.State, item.SavingBalance)));
// write to file
File.WriteAllText("d:\\temp\\file.csv", buffer.ToString());

输出结果为:

#key,name,sum
1,Item 1,10
20,Item 20,200
30,Item 30,300
40,Item 40,400
50,Item 50,500
70,Item 70,700

@aravol和@StephneKennedy提到的解决方案将如下所示:

public static class CSVWriter
{
    public static void write<T>(this IEnumerable<T> e, string file)
    {
        using (System.IO.StreamWriter f = new System.IO.StreamWriter(file))
        {
            foreach (var i in e)
            {
                f.WriteLine(i);
            }
        }
    }
}

可以像这样使用:

result.write<object>(file);

如前所述,此解决方案的问题在于您无法格式化输出,因为您正在使用Object.ToString方法而无法对其进行格式化(默认输出类似于{ key = value, key = value, ... }

如果您仍想将结果传输到另一个方法,则创建一个类型化的类并为每个结果条目创建一个对象(然后传输该列表)。示例类型类可以如下所示:

public class Placeholder
{
    public String Name { get; set; }
    public Int32 Index { get; set; }
    public Double Sum { get; set; }
}

然后更改LINQ查询以创建Placeholder的新对象,而不是匿名对象:

// test data
var data = new List<Int32> { 1, 20, 30, 40, 50, 70 };
var result = data.Select (d => new Placeholder
{
    Key = d,
    Name = String.Format("Item {0}", d),
    Sum = d * 10.0m
}).ToList();
result.write<Placeholder>("d:\\temp\\file.csv");

您的扩展方法可以直接使用write(this IEnumerable<Placeholder>...)或强制转换每个对象来使用类属性:

public static class CSVWriter
{
    public static void write<T>(this IEnumerable<T> e, string file)
    {
        using (System.IO.StreamWriter f = new System.IO.StreamWriter(file))
        {
            foreach (var i in e)
            {
                f.WriteLine(((Placeholder)i).Sum);
            }
        }
    }
}