C# 如何将对象列表转换为 csv?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2306667/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I convert a list of objects to csv?
提问by leora
If I have a list of objects called "Car":
如果我有一个名为“Car”的对象列表:
public class Car
{
public string Name;
public int Year;
public string Model;
}
How do I convert a list of objects, e.g. List<Car> to a csv?
如何将对象列表(例如 List<Car>)转换为 csv?
采纳答案by Sergey Mirvoda
- FileHelpersLibrary
- Text OleDb Provider
- Manual via String concatenation according to RFC-4180
- Third party library, for example Aspose.Cellscan do it without any friction from you. And it is veryfast.
- 文件助手库
- 文本 OleDb 提供程序
- 根据RFC-4180手动通过字符串连接
- 第三方库,例如Aspose.Cells可以做到这一点,而您没有任何摩擦。而且速度非常快。
回答by Oded
Look at the FileHelperslibrary.
查看FileHelpers库。
From the site:
从网站:
The FileHelpers are a free and easy to use .NET library to import/export data from fixed length or delimited records in files, strings or streams.
The FileHelpers are a free and easy to use .NET library to import/export data from fixed length or delimited records in files, strings or streams.
This will make sure that all kinds of gotchas in line termination, escaping and such are handled correctly, as per RFC-4180.
这将确保根据RFC-4180正确处理行终止、转义等各种问题。
回答by flq
Putting together comma-separated values I always like to point at the much underrated string.Join(string separator, string[] elements)
static method, but if there are helper libraries out there, that's probably better stuff.
将逗号分隔的值放在一起我总是喜欢指出被低估的string.Join(string separator, string[] elements)
静态方法,但如果那里有帮助库,那可能是更好的东西。
回答by Vlad
add the following method to Car:
将以下方法添加到 Car:
String Escape(String s)
{
StringBuilder sb = new StringBuilder();
bool needQuotes = false;
foreach (char c in s.ToArray())
{
switch (c)
{
case '"': sb.Append("\\""); needQuotes = true; break;
case ' ': sb.Append(" "); needQuotes = true; break;
case ',': sb.Append(","); needQuotes = true; break;
case '\t': sb.Append("\t"); needQuotes = true; break;
case '\n': sb.Append("\n"); needQuotes = true; break;
default: sb.Append(c); break;
}
}
if (needQuotes)
return "\"" + sb.ToString() + "\"";
else
return sb.ToString();
}
public void SerializeAsCsv(Stream stream)
{
stream.Write(Escape(Name));
stream.Write(",");
stream.Write(Year.ToString());
stream.Write(",");
stream.Write(Escape(Model));
stream.Write("\n");
}
Now you can serialize the whole list:
现在您可以序列化整个列表:
foreach (Car car in list)
{
car.SerializeAsCsv(stream);
}
回答by TheEruditeTroglodyte
I'd implement some addtional serialzation behaviors as per this article. If you want to get fancy, you can create a setting in your projects properties. This setting would determine if your class used csv or default serialialization. You'd then access it through the techniques shown here. Consider using a static constructor to read appsettings and make a boolean value accessable to your serialization code. Vlads' code looks great, just plug it in to your code. Also you can consider other, maybe more desirable ways to change your serialzation behavior.
我会按照这篇文章实现一些额外的序列化行为。如果你想变得更有趣,你可以在你的项目属性中创建一个设置。此设置将确定您的类是使用 csv 还是默认序列化。然后您可以通过此处显示的技术访问它。考虑使用静态构造函数来读取 appsettings 并使布尔值可访问您的序列化代码。Vlads 的代码看起来很棒,只需将其插入到您的代码中即可。您也可以考虑其他可能更理想的方法来更改您的序列化行为。
Or Create an interface called 'SerializeAsCSV' and use it kind of like this:
或者创建一个名为“SerializeAsCSV”的接口,并像这样使用它:
// Partial Contents of MyCoolClass.csv:
// MyCoolClass.csv 的部分内容:
public class MyCoolClass : ISerializeAsCSV, IDisposable
{
protected static bool serializesToCSV = false;
static MyCoolClass()
{
serializesToCSV =
(typeof(MyCoolClass).GetInterface("GrooveySoft.Shared.Interfaces.ISerializeAsCSV") == null)
? false
: true;
}
public MyCoolClass(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
{
// your stuff here
}
public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
{
// your stuff here
}
}
// contents of ISerializeAsCSV.cs
// ISerializeAsCSV.cs 的内容
using System.Runtime.Serialization;
namespace GrooveySoft.Shared.Interfaces
{
/// <summary>
/// indicates that implementor will serialize to csv format
/// </summary>
public interface ISerializeAsCSV : ISerializable
{
}
}
This should get your started . . . I haven't compiled and tested this . . but you get the general idea.
这应该让你开始。. . 我还没有编译和测试这个。. 但你明白了一般的想法。
回答by neontapir
Another option is Linq to CSV, a package available from NuGet. See Combine contents of two files using LINQ to CSVfor example usage.
另一种选择是Linq to CSV,这是 NuGet 提供的一个包。有关示例用法,请参阅使用 LINQ to CSV 合并两个文件的内容。
回答by Colin Wiseman
I was searching for a solution for this, but none of the answers I found satisfied my drive for simplicity. I realised I had the answer already with my auto CRUD code. I repurposed it and came up with the following code:
我正在为此寻找解决方案,但我找到的答案都没有满足我对简单性的追求。我意识到我的自动 CRUD 代码已经有了答案。我重新利用它并想出了以下代码:
using System.Reflection;
/// <summary>
/// Using a bit of reflection to build up the strings.
/// </summary>
public static string ToCsvHeader(this object obj)
{
Type type = obj.GetType();
var properties = type.GetProperties(BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.Instance);
string result = string.Empty;
Array.ForEach(properties, prop =>
{
result += prop.Name + ",";
});
return (!string.IsNullOrEmpty(result) ? result.Substring(0, result.Length - 1) : result);
}
public static string ToCsvRow(this object obj)
{
Type type = obj.GetType();
var properties = type.GetProperties(BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.Instance);
string result = string.Empty;
Array.ForEach(properties, prop =>
{
var value = prop.GetValue(obj, null);
var propertyType = prop.PropertyType.FullName;
if (propertyType == "System.String")
{
// wrap value incase of commas
value = "\"" + value + "\"";
}
result += value + ",";
});
return (!string.IsNullOrEmpty(result) ? result.Substring(0, result.Length - 1) : result);
}
This would add an extension method on to every object. Usage like this:
这将为每个对象添加一个扩展方法。用法如下:
var burgers = new List<Cheeseburger>();
var output = burgers.ToCsvHeader();
output += Environment.NewLine;
burgers.ForEach(burger =>
{
output += burger.ToCsvRow();
output += Environment.NewLine;
});
var path = "[where ever you want]";
System.IO.File.WriteAllText(path, output);
There is probably a better way to write these two methods above, but this works perfectly for my situation. Hope it helps someone.
可能有更好的方法来编写上面的这两种方法,但这对我的情况非常有效。希望它可以帮助某人。
回答by jdr1980
You could simply override the ToString method or create a ToCSVRow() method as such
您可以简单地覆盖 ToString 方法或创建一个 ToCSVRow() 方法
public String ToCSVRow()
{
return Name + "," + Year.ToString() + "," + Model;
}
And then just do something like this where needed.
然后在需要的地方做这样的事情。
using (StreamWriter file = new StreamWriter(@"C:\Wherever\yourfilename.txt"))
{
foreach (var item in yourlist)
{
file.WriteLine(item.ToCSVRow());
}
}