Tôi đang tìm một lớp để tạo tệp CSV Excel.
Các tính năng dự kiến:
- Sử dụng cực kỳ đơn giản
- Thoát dấu phẩy và dấu ngoặc kép để excel xử lý chúng tốt
- Xuất khẩu ngày và thời gian theo định dạng bằng múi giờ
Bạn có biết lớp nào có khả năng này không?
Tôi đang tìm một lớp để tạo tệp CSV Excel.
Các tính năng dự kiến:
Bạn có biết lớp nào có khả năng này không?
Câu trả lời:
Phiên bản hơi khác tôi đã viết bằng cách sử dụng sự phản ánh cho nhu cầu của tôi. Tôi đã phải xuất một danh sách các đối tượng sang csv. Trong trường hợp ai đó muốn sử dụng nó cho tương lai.
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;
}
}
Mẫu sử dụng: (cập nhật trên mỗi bình luận)
CsvExport<BusinessObject> csv= new CsvExport<BusinessObject>(GetBusinessObjectList());
Response.Write(csv.Export());
public string Export()
phương thức và thay đổi phương thức khác thành public string Export(bool includeHeaderLiner = true)
(với giá trị tham số mặc định). Một lần nữa, tôi không chắc liệu các tham số mặc định có khả dụng trong năm 2011 hay không, nhưng mã hiện tại chỉ mang tính chất onorthodox đối với tôi.
Xin hãy tha thứ cho tôi
Nhưng tôi nghĩ rằng một kho lưu trữ nguồn mở công khai là một cách tốt hơn để chia sẻ mã và đóng góp, sửa chữa và bổ sung như "Tôi đã sửa lỗi này, tôi đã sửa nó"
Vì vậy, tôi đã tạo một kho lưu trữ git đơn giản từ mã của trình khởi động chủ đề và tất cả các bổ sung:
https://github.com/jitbit/CsvExport
Tôi cũng đã thêm một vài sửa chữa hữu ích cho mình. Mọi người có thể thêm đề xuất, chia nó để đóng góp, v.v ... Gửi cho tôi dĩa của bạn để tôi hợp nhất chúng lại vào repo.
Tái bút Tôi đã đăng tất cả các thông báo bản quyền cho Chris. @Chris nếu bạn phản đối ý tưởng này - hãy cho tôi biết, tôi sẽ giết nó.
Một giải pháp tốt khác để đọc và ghi tệp CSV là trình trợ giúp tệp (nguồn mở).
Làm thế nào về việc sử dụng chuỗi.Join thay vì tất cả các vòng lặp foreach?
String.Join("," , List<string>)
cũng hoạt động.
Nếu bất cứ ai muốn tôi chuyển đổi nó thành một phương thức mở rộng trên 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;
}
}
công việc tuyệt vời trên lớp này Đơn giản và dễ sử dụng. Tôi đã sửa đổi lớp để bao gồm một tiêu đề trong hàng đầu tiên của xuất khẩu; Hình tôi sẽ chia sẻ:
sử dụng:
CsvExport myExport = new CsvExport();
myExport.addTitle = String.Format("Name: {0},{1}", lastName, firstName));
lớp học:
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());
}
}
có một thư viện mã nguồn mở cho CSV mà bạn có thể nhận được bằng cách sử dụng nuget: http://joshclose.github.io/CsvHelper/
Tôi đã thêm ExportToStream để csv không phải lưu vào ổ cứng trước.
public Stream ExportToStream()
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(Export(true));
writer.Flush();
stream.Position = 0;
return stream;
}
Tôi đã thêm
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);
}
Mã trước không hoạt động với các phiên bản .NET cũ. Đối với phiên bản 3.5 của khung, hãy sử dụng phiên bản khác này:
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());
}
Cảm ơn rất nhiều vì điều đó! Tôi đã sửa đổi lớp thành:
MakeValueCsvFriendly
Mã số:
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());
}
}
Bạn cũng có thể sử dụng ADO để làm điều này: http://weblogs.asp.net/fmarguerie/archive/2003/10/01/29964.aspx
Lớp ban đầu có một vấn đề và đó là nếu bạn muốn thêm một cột mới, bạn sẽ nhận được KeyNotFoundException về phương thức Xuất. Ví dụ:
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");
}
Để giải quyết vấn đề này và sử dụng ý tưởng @PalCowboy sử dụng sự phản chiếu, tôi đã sửa đổi mã để cho phép thêm các hàng không có cùng cột. Bạn có thể sử dụng các thể hiện của các lớp ẩn danh. Ví dụ:
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");
}
Bạn có thể tải mã nguồn tại đây CsvExporter . Hãy sử dụng và sửa đổi.
Bây giờ, nếu tất cả các hàng bạn muốn viết đều thuộc cùng một lớp, tôi đã tạo lớp chung CsvWriter.cs , có mức sử dụng RAM hiệu suất tốt hơn và lý tưởng để ghi các tệp lớn. Thêm vào đó, nó cho phép bạn thêm trình định dạng vào loại dữ liệu bạn muốn . Một ví dụ về sử dụng:
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; }
}
Bạn chỉ cần 1 chức năng để làm điều này. Chỉ có bạn phải làm là tạo một thư mục trong trình khám phá giải pháp của bạn và lưu trữ tệp csv ở đó và sau đó xuất tệp đó cho người dùng.
Như trong trường hợp của tôi, tôi có một thư mục tải về. Đầu tiên tôi xuất tất cả nội dung của mình vào thư mục đó và sau đó xuất nó cho người dùng. Để xử lý answer.end, tôi đã sử dụng ThreadAdortException. Vì vậy, nó là một chức năng chính hãng và làm việc 100% trong giải pháp của tôi.
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....
}