I'm looking for a class for creating CSV Excel files.
我在找一个创建CSV Excel文件的类。
Expected features:
预期的特点:
- Extremely simple to use
- 非常简单易用
- Escapes commas and quotes so excel handles them fine
- 转义逗号和引号,因此excel可以很好地处理它们
- Exports date and datetimes in timezone-proof format
- 以时间区域证明格式导出日期和日期时间
Do you know any class capable of this?
你知道有什么班能做到这一点吗?
13 个解决方案
#1
91
Slightly different version I wrote using reflection for my needs. I had to export a list of objects to csv. In case someone wants to use it for future.
根据我的需要,我使用反射编写了稍微不同的版本。我必须向csv导出一个对象列表。以防有人想用它来做未来。
public class CsvExport<T> where T: class
{
public List<T> Objects;
public CsvExport(List<T> objects)
{
Objects = objects;
}
public string Export()
{
return Export(true);
}
public string Export(bool includeHeaderLine)
{
StringBuilder sb = new StringBuilder();
//Get properties using reflection.
IList<PropertyInfo> propertyInfos = typeof(T).GetProperties();
if (includeHeaderLine)
{
//add header line.
foreach (PropertyInfo propertyInfo in propertyInfos)
{
sb.Append(propertyInfo.Name).Append(",");
}
sb.Remove(sb.Length - 1, 1).AppendLine();
}
//add value for each property.
foreach (T obj in Objects)
{
foreach (PropertyInfo propertyInfo in propertyInfos)
{
sb.Append(MakeValueCsvFriendly(propertyInfo.GetValue(obj, null))).Append(",");
}
sb.Remove(sb.Length - 1, 1).AppendLine();
}
return sb.ToString();
}
//export to a file.
public void ExportToFile(string path)
{
File.WriteAllText(path, Export());
}
//export as binary data.
public byte[] ExportToBytes()
{
return Encoding.UTF8.GetBytes(Export());
}
//get the csv value for field.
private string MakeValueCsvFriendly(object value)
{
if (value == null) return "";
if (value is Nullable && ((INullable)value).IsNull) return "";
if (value is DateTime)
{
if (((DateTime)value).TimeOfDay.TotalSeconds == 0)
return ((DateTime)value).ToString("yyyy-MM-dd");
return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
}
string output = value.ToString();
if (output.Contains(",") || output.Contains("\""))
output = '"' + output.Replace("\"", "\"\"") + '"';
return output;
}
}
Usage sample : (updated per comment)
用法示例:(每条评论更新一次)
CsvExport<BusinessObject> csv= new CsvExport<BusinessObject>(GetBusinessObjectList());
Response.Write(csv.Export());
#2
18
Please forgive me
请原谅我
But I think a public open-source repository is a better way to share code and make contributions, and corrections, and additions like "I fixed this, I fixed that"
但是我认为公共开源存储库是一种更好的共享代码,贡献,修正和补充的方式比如"我修复了这个,我修复了那个"
So I made a simple git-repository out of the topic-starter's code and all the additions:
所以我用主题启动器的代码和所有添加的代码做了一个简单的git仓库:
https://github.com/jitbit/CsvExport
https://github.com/jitbit/CsvExport
I also added a couple of useful fixes myself. Everyone could add suggestions, fork it to contribute etc. etc. etc. Send me your forks so I merge them back into the repo.
我还添加了一些有用的修正。每个人都可以添加建议,分叉贡献等等。把你的分叉发给我,这样我就可以把它们合并回回购。
PS. I posted all copyright notices for Chris. @Chris if you're against this idea - let me know, I'll kill it.
PS.我为Chris贴了所有的版权通知。@Chris,如果你反对这个想法-让我知道,我会杀了它。
#3
11
Another good solution to read and write CSV-files is filehelpers (open source).
另一个读写csv文件的好方法是filehelper(开源)。
#4
6
How about using string.Join instead of all the foreach Loops?
如何使用字符串。连接而不是所有的foreach循环?
#5
6
If anyone would like I converted this to an extension method on IEnumerable:
如果有人愿意,我把它转换成IEnumerable的扩展方法:
public static class ListExtensions
{
public static string ExportAsCSV<T>(this IEnumerable<T> listToExport, bool includeHeaderLine, string delimeter)
{
StringBuilder sb = new StringBuilder();
IList<PropertyInfo> propertyInfos = typeof(T).GetProperties();
if (includeHeaderLine)
{
foreach (PropertyInfo propertyInfo in propertyInfos)
{
sb.Append(propertyInfo.Name).Append(",");
}
sb.Remove(sb.Length - 1, 1).AppendLine();
}
foreach (T obj in listToExport)
{
T localObject = obj;
var line = String.Join(delimeter, propertyInfos.Select(x => SanitizeValuesForCSV(x.GetValue(localObject, null), delimeter)));
sb.AppendLine(line);
}
return sb.ToString();
}
private static string SanitizeValuesForCSV(object value, string delimeter)
{
string output;
if (value == null) return "";
if (value is DateTime)
{
output = ((DateTime)value).ToLongDateString();
}
else
{
output = value.ToString();
}
if (output.Contains(delimeter) || output.Contains("\""))
output = '"' + output.Replace("\"", "\"\"") + '"';
output = output.Replace("\n", " ");
output = output.Replace("\r", "");
return output;
}
}
#6
5
great work on this class. Simple and easy to use. I modified the class to include a title in the first row of the export; figured I would share:
这门课做得很好。简单易用。我将类修改为在导出的第一行包含一个标题;算我想分享:
use:
使用:
CsvExport myExport = new CsvExport();
myExport.addTitle = String.Format("Name: {0},{1}", lastName, firstName));
class:
类:
public class CsvExport
{
List<string> fields = new List<string>();
public string addTitle { get; set; } // string for the first row of the export
List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
Dictionary<string, object> currentRow
{
get
{
return rows[rows.Count - 1];
}
}
public object this[string field]
{
set
{
if (!fields.Contains(field)) fields.Add(field);
currentRow[field] = value;
}
}
public void AddRow()
{
rows.Add(new Dictionary<string, object>());
}
string MakeValueCsvFriendly(object value)
{
if (value == null) return "";
if (value is Nullable && ((INullable)value).IsNull) return "";
if (value is DateTime)
{
if (((DateTime)value).TimeOfDay.TotalSeconds == 0)
return ((DateTime)value).ToString("yyyy-MM-dd");
return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
}
string output = value.ToString();
if (output.Contains(",") || output.Contains("\""))
output = '"' + output.Replace("\"", "\"\"") + '"';
return output;
}
public string Export()
{
StringBuilder sb = new StringBuilder();
// if there is a title
if (!string.IsNullOrEmpty(addTitle))
{
// escape chars that would otherwise break the row / export
char[] csvTokens = new[] { '\"', ',', '\n', '\r' };
if (addTitle.IndexOfAny(csvTokens) >= 0)
{
addTitle = "\"" + addTitle.Replace("\"", "\"\"") + "\"";
}
sb.Append(addTitle).Append(",");
sb.AppendLine();
}
// The header
foreach (string field in fields)
sb.Append(field).Append(",");
sb.AppendLine();
// The rows
foreach (Dictionary<string, object> row in rows)
{
foreach (string field in fields)
sb.Append(MakeValueCsvFriendly(row[field])).Append(",");
sb.AppendLine();
}
return sb.ToString();
}
public void ExportToFile(string path)
{
File.WriteAllText(path, Export());
}
public byte[] ExportToBytes()
{
return Encoding.UTF8.GetBytes(Export());
}
}
#7
4
there's an open-source library for CSV which you can get using nuget: http://joshclose.github.io/CsvHelper/
有一个用于CSV的开源库,可以使用nuget: http://joshclose.github.io/CsvHelper/
#8
3
I added ExportToStream so the csv didn't have to save to the hard drive first.
我添加了ExportToStream,这样csv就不必先保存到硬盘上。
public Stream ExportToStream()
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(Export(true));
writer.Flush();
stream.Position = 0;
return stream;
}
#9
3
I've added
我已经添加了
public void ExportToFile(string path, DataTable tabela)
{
DataColumnCollection colunas = tabela.Columns;
foreach (DataRow linha in tabela.Rows)
{
this.AddRow();
foreach (DataColumn coluna in colunas)
{
this[coluna.ColumnName] = linha[coluna];
}
}
this.ExportToFile(path);
}
Previous code does not work with old .NET versions. For 3.5 version of framework use this other version:
以前的代码不能使用旧的。net版本。3.5版本的框架使用其他版本:
public void ExportToFile(string path)
{
bool abort = false;
bool exists = false;
do
{
exists = File.Exists(path);
if (!exists)
{
if( !Convert.ToBoolean( File.CreateText(path) ) )
abort = true;
}
} while (!exists || abort);
if (!abort)
{
//File.OpenWrite(path);
using (StreamWriter w = File.AppendText(path))
{
w.WriteLine("hello");
}
}
//File.WriteAllText(path, Export());
}
#10
2
Thanks a lot for that! I modified the class to:
非常感谢!我修改了这个类:
- use a variable delimiter, instead of hardcoded in code
- 使用变量分隔符,而不是硬编码在代码中
- replacing all newLines (\n \r \n\r) in
MakeValueCsvFriendly
- 在MakeValueCsvFriendly中替换所有新行
Code:
代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.SqlTypes;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
public class CsvExport
{
public char delim = ';';
/// <summary>
/// To keep the ordered list of column names
/// </summary>
List<string> fields = new List<string>();
/// <summary>
/// The list of rows
/// </summary>
List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
/// <summary>
/// The current row
/// </summary>
Dictionary<string, object> currentRow { get { return rows[rows.Count - 1]; } }
/// <summary>
/// Set a value on this column
/// </summary>
public object this[string field]
{
set
{
// Keep track of the field names, because the dictionary loses the ordering
if (!fields.Contains(field)) fields.Add(field);
currentRow[field] = value;
}
}
/// <summary>
/// Call this before setting any fields on a row
/// </summary>
public void AddRow()
{
rows.Add(new Dictionary<string, object>());
}
/// <summary>
/// Converts a value to how it should output in a csv file
/// If it has a comma, it needs surrounding with double quotes
/// Eg Sydney, Australia -> "Sydney, Australia"
/// Also if it contains any double quotes ("), then they need to be replaced with quad quotes[sic] ("")
/// Eg "Dangerous Dan" McGrew -> """Dangerous Dan"" McGrew"
/// </summary>
string MakeValueCsvFriendly(object value)
{
if (value == null) return "";
if (value is INullable && ((INullable)value).IsNull) return "";
if (value is DateTime)
{
if (((DateTime)value).TimeOfDay.TotalSeconds == 0)
return ((DateTime)value).ToString("yyyy-MM-dd");
return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
}
string output = value.ToString();
if (output.Contains(delim) || output.Contains("\""))
output = '"' + output.Replace("\"", "\"\"") + '"';
if (Regex.IsMatch(output, @"(?:\r\n|\n|\r)"))
output = string.Join(" ", Regex.Split(output, @"(?:\r\n|\n|\r)"));
return output;
}
/// <summary>
/// Output all rows as a CSV returning a string
/// </summary>
public string Export()
{
StringBuilder sb = new StringBuilder();
// The header
foreach (string field in fields)
sb.Append(field).Append(delim);
sb.AppendLine();
// The rows
foreach (Dictionary<string, object> row in rows)
{
foreach (string field in fields)
sb.Append(MakeValueCsvFriendly(row[field])).Append(delim);
sb.AppendLine();
}
return sb.ToString();
}
/// <summary>
/// Exports to a file
/// </summary>
public void ExportToFile(string path)
{
File.WriteAllText(path, Export());
}
/// <summary>
/// Exports as raw UTF8 bytes
/// </summary>
public byte[] ExportToBytes()
{
return Encoding.UTF8.GetBytes(Export());
}
}
#11
1
You can also use ADO to do this: http://weblogs.asp.net/fmarguerie/archive/2003/10/01/29964.aspx
您还可以使用ADO来实现这一点:http://weblogs.asp.net/fmarguerie/archive/2003/10/01/29964.aspx
#12
1
The original class have a problem, and that is if you want to add a new column, you will receive KeyNotFoundException on Export method. For example:
原始类有一个问题,那就是如果您想添加一个新的列,您将接收到Export方法的KeyNotFoundException。例如:
static void Main(string[] args)
{
var export = new CsvExport();
export.AddRow();
export["Region"] = "New York, USA";
export["Sales"] = 100000;
export["Date Opened"] = new DateTime(2003, 12, 31);
export.AddRow();
export["Region"] = "Sydney \"in\" Australia";
export["Sales"] = 50000;
export["Date Opened"] = new DateTime(2005, 1, 1, 9, 30, 0);
export["Balance"] = 3.45f; //Exception is throwed for this new column
export.ExportToFile("Somefile.csv");
}
To solve this, and using the @KeyboardCowboy idea of using reflection, I modified the code to allow add rows that do not have the same columns. You can use instances of anonymous classes. For example:
为了解决这个问题,并使用了使用反射的@KeyboardCowboy概念,我修改了代码,允许添加没有相同列的行。您可以使用匿名类的实例。例如:
static void Main(string[] args)
{
var export = new CsvExporter();
export.AddRow(new {A = 12, B = "Empty"});
export.AddRow(new {A = 34.5f, D = false});
export.ExportToFile("File.csv");
}
You can download the source code here CsvExporter. Feel free to use and modify.
您可以在这里下载csvexports的源代码。请随意使用和修改。
Now, if all rows you want to write are of the same class, I created the generic class CsvWriter.cs, which has a better performance RAM usage and ideal for writing large files.Plus it lets you add formatters to the data type you want. An example of use:
现在,如果要编写的所有行都属于同一个类,我创建了通用类CsvWriter。cs,具有更好的性能RAM使用,非常适合编写大型文件。此外,它还允许向所需的数据类型添加格式化程序。使用一个例子:
class Program
{
static void Main(string[] args)
{
var writer = new CsvWriter<Person>("Persons.csv");
writer.AddFormatter<DateTime>(d => d.ToString("MM/dd/yyyy"));
writer.WriteHeaders();
writer.WriteRows(GetPersons());
writer.Flush();
writer.Close();
}
private static IEnumerable<Person> GetPersons()
{
yield return new Person
{
FirstName = "Jhon",
LastName = "Doe",
Sex = 'M'
};
yield return new Person
{
FirstName = "Jhane",
LastName = "Doe",
Sex = 'F',
BirthDate = DateTime.Now
};
}
}
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public char Sex { get; set; }
public DateTime BirthDate { get; set; }
}
#13
0
You need only 1 function to do this. Only you have to do is to make a folder in your solution explorer and store the csv file there and then export that file to the user.
只需要一个函数。您只需在解决方案资源管理器中创建一个文件夹,并在其中存储csv文件,然后将该文件导出给用户。
As in my case I have a folder downloads. First I export all my content to that directory and then exporting it to the user. For response.end handling, I used the ThreadAbortException. So it is a 100% genuine and working function in my solution.
在我的例子中,我有一个文件夹下载。首先,我将所有内容导出到该目录,然后将其导出到用户。为响应。结束处理,我使用了ThreadAbortException。所以在我的解中它是一个100%真实的工作函数。
protected void lnkExport_OnClick(object sender, EventArgs e)
{
string filename = strFileName = "Export.csv";
DataTable dt = obj.GetData();
// call the content and load it into the datatable
strFileName = Server.MapPath("Downloads") + "\\" + strFileName;
// creating a file in the downloads folder in your solution explorer
TextWriter tw = new StreamWriter(strFileName);
// using the built in class textwriter for writing your content in the exporting file
string strData = "Username,Password,City";
// above line is the header for your exported file. So add headings for your coloumns in excel(.csv) file and seperate them with ","
strData += Environment.NewLine;
// setting the environment to the new line
foreach (DataRow dr in dt.Rows)
{
strData += dr["Username"].ToString() + "," + dr["Password"].ToString() + "," + dr["City"].ToString();
strData += Environment.NewLine;
}
// everytime when loop execute, it adds a line into the file
tw.Write(strData);
// writing the contents in file
tw.Close();
// closing the file
Response.Redirect("Downloads/" + filename);
// exporting the file to the user as a popup to save as....
}
#1
91
Slightly different version I wrote using reflection for my needs. I had to export a list of objects to csv. In case someone wants to use it for future.
根据我的需要,我使用反射编写了稍微不同的版本。我必须向csv导出一个对象列表。以防有人想用它来做未来。
public class CsvExport<T> where T: class
{
public List<T> Objects;
public CsvExport(List<T> objects)
{
Objects = objects;
}
public string Export()
{
return Export(true);
}
public string Export(bool includeHeaderLine)
{
StringBuilder sb = new StringBuilder();
//Get properties using reflection.
IList<PropertyInfo> propertyInfos = typeof(T).GetProperties();
if (includeHeaderLine)
{
//add header line.
foreach (PropertyInfo propertyInfo in propertyInfos)
{
sb.Append(propertyInfo.Name).Append(",");
}
sb.Remove(sb.Length - 1, 1).AppendLine();
}
//add value for each property.
foreach (T obj in Objects)
{
foreach (PropertyInfo propertyInfo in propertyInfos)
{
sb.Append(MakeValueCsvFriendly(propertyInfo.GetValue(obj, null))).Append(",");
}
sb.Remove(sb.Length - 1, 1).AppendLine();
}
return sb.ToString();
}
//export to a file.
public void ExportToFile(string path)
{
File.WriteAllText(path, Export());
}
//export as binary data.
public byte[] ExportToBytes()
{
return Encoding.UTF8.GetBytes(Export());
}
//get the csv value for field.
private string MakeValueCsvFriendly(object value)
{
if (value == null) return "";
if (value is Nullable && ((INullable)value).IsNull) return "";
if (value is DateTime)
{
if (((DateTime)value).TimeOfDay.TotalSeconds == 0)
return ((DateTime)value).ToString("yyyy-MM-dd");
return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
}
string output = value.ToString();
if (output.Contains(",") || output.Contains("\""))
output = '"' + output.Replace("\"", "\"\"") + '"';
return output;
}
}
Usage sample : (updated per comment)
用法示例:(每条评论更新一次)
CsvExport<BusinessObject> csv= new CsvExport<BusinessObject>(GetBusinessObjectList());
Response.Write(csv.Export());
#2
18
Please forgive me
请原谅我
But I think a public open-source repository is a better way to share code and make contributions, and corrections, and additions like "I fixed this, I fixed that"
但是我认为公共开源存储库是一种更好的共享代码,贡献,修正和补充的方式比如"我修复了这个,我修复了那个"
So I made a simple git-repository out of the topic-starter's code and all the additions:
所以我用主题启动器的代码和所有添加的代码做了一个简单的git仓库:
https://github.com/jitbit/CsvExport
https://github.com/jitbit/CsvExport
I also added a couple of useful fixes myself. Everyone could add suggestions, fork it to contribute etc. etc. etc. Send me your forks so I merge them back into the repo.
我还添加了一些有用的修正。每个人都可以添加建议,分叉贡献等等。把你的分叉发给我,这样我就可以把它们合并回回购。
PS. I posted all copyright notices for Chris. @Chris if you're against this idea - let me know, I'll kill it.
PS.我为Chris贴了所有的版权通知。@Chris,如果你反对这个想法-让我知道,我会杀了它。
#3
11
Another good solution to read and write CSV-files is filehelpers (open source).
另一个读写csv文件的好方法是filehelper(开源)。
#4
6
How about using string.Join instead of all the foreach Loops?
如何使用字符串。连接而不是所有的foreach循环?
#5
6
If anyone would like I converted this to an extension method on IEnumerable:
如果有人愿意,我把它转换成IEnumerable的扩展方法:
public static class ListExtensions
{
public static string ExportAsCSV<T>(this IEnumerable<T> listToExport, bool includeHeaderLine, string delimeter)
{
StringBuilder sb = new StringBuilder();
IList<PropertyInfo> propertyInfos = typeof(T).GetProperties();
if (includeHeaderLine)
{
foreach (PropertyInfo propertyInfo in propertyInfos)
{
sb.Append(propertyInfo.Name).Append(",");
}
sb.Remove(sb.Length - 1, 1).AppendLine();
}
foreach (T obj in listToExport)
{
T localObject = obj;
var line = String.Join(delimeter, propertyInfos.Select(x => SanitizeValuesForCSV(x.GetValue(localObject, null), delimeter)));
sb.AppendLine(line);
}
return sb.ToString();
}
private static string SanitizeValuesForCSV(object value, string delimeter)
{
string output;
if (value == null) return "";
if (value is DateTime)
{
output = ((DateTime)value).ToLongDateString();
}
else
{
output = value.ToString();
}
if (output.Contains(delimeter) || output.Contains("\""))
output = '"' + output.Replace("\"", "\"\"") + '"';
output = output.Replace("\n", " ");
output = output.Replace("\r", "");
return output;
}
}
#6
5
great work on this class. Simple and easy to use. I modified the class to include a title in the first row of the export; figured I would share:
这门课做得很好。简单易用。我将类修改为在导出的第一行包含一个标题;算我想分享:
use:
使用:
CsvExport myExport = new CsvExport();
myExport.addTitle = String.Format("Name: {0},{1}", lastName, firstName));
class:
类:
public class CsvExport
{
List<string> fields = new List<string>();
public string addTitle { get; set; } // string for the first row of the export
List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
Dictionary<string, object> currentRow
{
get
{
return rows[rows.Count - 1];
}
}
public object this[string field]
{
set
{
if (!fields.Contains(field)) fields.Add(field);
currentRow[field] = value;
}
}
public void AddRow()
{
rows.Add(new Dictionary<string, object>());
}
string MakeValueCsvFriendly(object value)
{
if (value == null) return "";
if (value is Nullable && ((INullable)value).IsNull) return "";
if (value is DateTime)
{
if (((DateTime)value).TimeOfDay.TotalSeconds == 0)
return ((DateTime)value).ToString("yyyy-MM-dd");
return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
}
string output = value.ToString();
if (output.Contains(",") || output.Contains("\""))
output = '"' + output.Replace("\"", "\"\"") + '"';
return output;
}
public string Export()
{
StringBuilder sb = new StringBuilder();
// if there is a title
if (!string.IsNullOrEmpty(addTitle))
{
// escape chars that would otherwise break the row / export
char[] csvTokens = new[] { '\"', ',', '\n', '\r' };
if (addTitle.IndexOfAny(csvTokens) >= 0)
{
addTitle = "\"" + addTitle.Replace("\"", "\"\"") + "\"";
}
sb.Append(addTitle).Append(",");
sb.AppendLine();
}
// The header
foreach (string field in fields)
sb.Append(field).Append(",");
sb.AppendLine();
// The rows
foreach (Dictionary<string, object> row in rows)
{
foreach (string field in fields)
sb.Append(MakeValueCsvFriendly(row[field])).Append(",");
sb.AppendLine();
}
return sb.ToString();
}
public void ExportToFile(string path)
{
File.WriteAllText(path, Export());
}
public byte[] ExportToBytes()
{
return Encoding.UTF8.GetBytes(Export());
}
}
#7
4
there's an open-source library for CSV which you can get using nuget: http://joshclose.github.io/CsvHelper/
有一个用于CSV的开源库,可以使用nuget: http://joshclose.github.io/CsvHelper/
#8
3
I added ExportToStream so the csv didn't have to save to the hard drive first.
我添加了ExportToStream,这样csv就不必先保存到硬盘上。
public Stream ExportToStream()
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(Export(true));
writer.Flush();
stream.Position = 0;
return stream;
}
#9
3
I've added
我已经添加了
public void ExportToFile(string path, DataTable tabela)
{
DataColumnCollection colunas = tabela.Columns;
foreach (DataRow linha in tabela.Rows)
{
this.AddRow();
foreach (DataColumn coluna in colunas)
{
this[coluna.ColumnName] = linha[coluna];
}
}
this.ExportToFile(path);
}
Previous code does not work with old .NET versions. For 3.5 version of framework use this other version:
以前的代码不能使用旧的。net版本。3.5版本的框架使用其他版本:
public void ExportToFile(string path)
{
bool abort = false;
bool exists = false;
do
{
exists = File.Exists(path);
if (!exists)
{
if( !Convert.ToBoolean( File.CreateText(path) ) )
abort = true;
}
} while (!exists || abort);
if (!abort)
{
//File.OpenWrite(path);
using (StreamWriter w = File.AppendText(path))
{
w.WriteLine("hello");
}
}
//File.WriteAllText(path, Export());
}
#10
2
Thanks a lot for that! I modified the class to:
非常感谢!我修改了这个类:
- use a variable delimiter, instead of hardcoded in code
- 使用变量分隔符,而不是硬编码在代码中
- replacing all newLines (\n \r \n\r) in
MakeValueCsvFriendly
- 在MakeValueCsvFriendly中替换所有新行
Code:
代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.SqlTypes;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
public class CsvExport
{
public char delim = ';';
/// <summary>
/// To keep the ordered list of column names
/// </summary>
List<string> fields = new List<string>();
/// <summary>
/// The list of rows
/// </summary>
List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
/// <summary>
/// The current row
/// </summary>
Dictionary<string, object> currentRow { get { return rows[rows.Count - 1]; } }
/// <summary>
/// Set a value on this column
/// </summary>
public object this[string field]
{
set
{
// Keep track of the field names, because the dictionary loses the ordering
if (!fields.Contains(field)) fields.Add(field);
currentRow[field] = value;
}
}
/// <summary>
/// Call this before setting any fields on a row
/// </summary>
public void AddRow()
{
rows.Add(new Dictionary<string, object>());
}
/// <summary>
/// Converts a value to how it should output in a csv file
/// If it has a comma, it needs surrounding with double quotes
/// Eg Sydney, Australia -> "Sydney, Australia"
/// Also if it contains any double quotes ("), then they need to be replaced with quad quotes[sic] ("")
/// Eg "Dangerous Dan" McGrew -> """Dangerous Dan"" McGrew"
/// </summary>
string MakeValueCsvFriendly(object value)
{
if (value == null) return "";
if (value is INullable && ((INullable)value).IsNull) return "";
if (value is DateTime)
{
if (((DateTime)value).TimeOfDay.TotalSeconds == 0)
return ((DateTime)value).ToString("yyyy-MM-dd");
return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
}
string output = value.ToString();
if (output.Contains(delim) || output.Contains("\""))
output = '"' + output.Replace("\"", "\"\"") + '"';
if (Regex.IsMatch(output, @"(?:\r\n|\n|\r)"))
output = string.Join(" ", Regex.Split(output, @"(?:\r\n|\n|\r)"));
return output;
}
/// <summary>
/// Output all rows as a CSV returning a string
/// </summary>
public string Export()
{
StringBuilder sb = new StringBuilder();
// The header
foreach (string field in fields)
sb.Append(field).Append(delim);
sb.AppendLine();
// The rows
foreach (Dictionary<string, object> row in rows)
{
foreach (string field in fields)
sb.Append(MakeValueCsvFriendly(row[field])).Append(delim);
sb.AppendLine();
}
return sb.ToString();
}
/// <summary>
/// Exports to a file
/// </summary>
public void ExportToFile(string path)
{
File.WriteAllText(path, Export());
}
/// <summary>
/// Exports as raw UTF8 bytes
/// </summary>
public byte[] ExportToBytes()
{
return Encoding.UTF8.GetBytes(Export());
}
}
#11
1
You can also use ADO to do this: http://weblogs.asp.net/fmarguerie/archive/2003/10/01/29964.aspx
您还可以使用ADO来实现这一点:http://weblogs.asp.net/fmarguerie/archive/2003/10/01/29964.aspx
#12
1
The original class have a problem, and that is if you want to add a new column, you will receive KeyNotFoundException on Export method. For example:
原始类有一个问题,那就是如果您想添加一个新的列,您将接收到Export方法的KeyNotFoundException。例如:
static void Main(string[] args)
{
var export = new CsvExport();
export.AddRow();
export["Region"] = "New York, USA";
export["Sales"] = 100000;
export["Date Opened"] = new DateTime(2003, 12, 31);
export.AddRow();
export["Region"] = "Sydney \"in\" Australia";
export["Sales"] = 50000;
export["Date Opened"] = new DateTime(2005, 1, 1, 9, 30, 0);
export["Balance"] = 3.45f; //Exception is throwed for this new column
export.ExportToFile("Somefile.csv");
}
To solve this, and using the @KeyboardCowboy idea of using reflection, I modified the code to allow add rows that do not have the same columns. You can use instances of anonymous classes. For example:
为了解决这个问题,并使用了使用反射的@KeyboardCowboy概念,我修改了代码,允许添加没有相同列的行。您可以使用匿名类的实例。例如:
static void Main(string[] args)
{
var export = new CsvExporter();
export.AddRow(new {A = 12, B = "Empty"});
export.AddRow(new {A = 34.5f, D = false});
export.ExportToFile("File.csv");
}
You can download the source code here CsvExporter. Feel free to use and modify.
您可以在这里下载csvexports的源代码。请随意使用和修改。
Now, if all rows you want to write are of the same class, I created the generic class CsvWriter.cs, which has a better performance RAM usage and ideal for writing large files.Plus it lets you add formatters to the data type you want. An example of use:
现在,如果要编写的所有行都属于同一个类,我创建了通用类CsvWriter。cs,具有更好的性能RAM使用,非常适合编写大型文件。此外,它还允许向所需的数据类型添加格式化程序。使用一个例子:
class Program
{
static void Main(string[] args)
{
var writer = new CsvWriter<Person>("Persons.csv");
writer.AddFormatter<DateTime>(d => d.ToString("MM/dd/yyyy"));
writer.WriteHeaders();
writer.WriteRows(GetPersons());
writer.Flush();
writer.Close();
}
private static IEnumerable<Person> GetPersons()
{
yield return new Person
{
FirstName = "Jhon",
LastName = "Doe",
Sex = 'M'
};
yield return new Person
{
FirstName = "Jhane",
LastName = "Doe",
Sex = 'F',
BirthDate = DateTime.Now
};
}
}
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public char Sex { get; set; }
public DateTime BirthDate { get; set; }
}
#13
0
You need only 1 function to do this. Only you have to do is to make a folder in your solution explorer and store the csv file there and then export that file to the user.
只需要一个函数。您只需在解决方案资源管理器中创建一个文件夹,并在其中存储csv文件,然后将该文件导出给用户。
As in my case I have a folder downloads. First I export all my content to that directory and then exporting it to the user. For response.end handling, I used the ThreadAbortException. So it is a 100% genuine and working function in my solution.
在我的例子中,我有一个文件夹下载。首先,我将所有内容导出到该目录,然后将其导出到用户。为响应。结束处理,我使用了ThreadAbortException。所以在我的解中它是一个100%真实的工作函数。
protected void lnkExport_OnClick(object sender, EventArgs e)
{
string filename = strFileName = "Export.csv";
DataTable dt = obj.GetData();
// call the content and load it into the datatable
strFileName = Server.MapPath("Downloads") + "\\" + strFileName;
// creating a file in the downloads folder in your solution explorer
TextWriter tw = new StreamWriter(strFileName);
// using the built in class textwriter for writing your content in the exporting file
string strData = "Username,Password,City";
// above line is the header for your exported file. So add headings for your coloumns in excel(.csv) file and seperate them with ","
strData += Environment.NewLine;
// setting the environment to the new line
foreach (DataRow dr in dt.Rows)
{
strData += dr["Username"].ToString() + "," + dr["Password"].ToString() + "," + dr["City"].ToString();
strData += Environment.NewLine;
}
// everytime when loop execute, it adds a line into the file
tw.Write(strData);
// writing the contents in file
tw.Close();
// closing the file
Response.Redirect("Downloads/" + filename);
// exporting the file to the user as a popup to save as....
}