将datagridview导出到csv文件
Posted
技术标签:
【中文标题】将datagridview导出到csv文件【英文标题】:Exporting datagridview to csv file 【发布时间】:2012-04-14 04:28:42 【问题描述】:我正在开发一个应用程序,它将我的名为scannerDataGridView 的DataGridView 导出到一个csv 文件。
找到了一些示例代码来执行此操作,但无法使其正常工作。顺便说一句,我的数据网格没有数据绑定到源。
当我尝试使用 Streamwriter 仅写入列标题时,一切顺利,但是当我尝试导出包括数据在内的整个数据网格时,我得到了一个例外。
System.NullReferenceException:对象引用未设置为实例 的一个对象。在 Scanmonitor.Form1.button1_Click(对象发件人, 事件参数 e)
这是我的代码,以下行给出了错误:
dataFromGrid = dataFromGrid + ',' + dataRowObject.Cells[i].Value.ToString();
//csvFileWriter = StreamWriter
//scannerDataGridView = DataGridView
private void button1_Click(object sender, EventArgs e)
string CsvFpath = @"C:\scanner\CSV-EXPORT.csv";
try
System.IO.StreamWriter csvFileWriter = new StreamWriter(CsvFpath, false);
string columnHeaderText = "";
int countColumn = scannerDataGridView.ColumnCount - 1;
if (countColumn >= 0)
columnHeaderText = scannerDataGridView.Columns[0].HeaderText;
for (int i = 1; i <= countColumn; i++)
columnHeaderText = columnHeaderText + ',' + scannerDataGridView.Columns[i].HeaderText;
csvFileWriter.WriteLine(columnHeaderText);
foreach (DataGridViewRow dataRowObject in scannerDataGridView.Rows)
if (!dataRowObject.IsNewRow)
string dataFromGrid = "";
dataFromGrid = dataRowObject.Cells[0].Value.ToString();
for (int i = 1; i <= countColumn; i++)
dataFromGrid = dataFromGrid + ',' + dataRowObject.Cells[i].Value.ToString();
csvFileWriter.WriteLine(dataFromGrid);
csvFileWriter.Flush();
csvFileWriter.Close();
catch (Exception exceptionObject)
MessageBox.Show(exceptionObject.ToString());
【问题讨论】:
在哪一行抛出异常?您也可以使用 foreach 来遍历每一行的列:foreach(dataRowObject.Cells 中的 DataGridViewCell 单元格),除非有特定原因您更喜欢正常的 for 循环? 也可以检查scannerDataGridView.Rows.Count > 0 嗨 PandaNL,我已经删除了我的答案。我仍然认为违规行应该是object value = dataRowObject.Cells[i].Value; dataFromGrid = dataFromGrid + ',' + (value ?? string.Empty).ToString());
在close()之前不需要flush()。 Dispose() 调用 Close() 并调用 flush()。
【参考方案1】:
LINQ FTW!
var sb = new StringBuilder();
var headers = dataGridView1.Columns.Cast<DataGridViewColumn>();
sb.AppendLine(string.Join(",", headers.Select(column => "\"" + column.HeaderText + "\"").ToArray()));
foreach (DataGridViewRow row in dataGridView1.Rows)
var cells = row.Cells.Cast<DataGridViewCell>();
sb.AppendLine(string.Join(",", cells.Select(cell => "\"" + cell.Value + "\"").ToArray()));
确实,c.Value.ToString()
将抛出空值,而c.Value
将正确转换为空字符串。
【讨论】:
我在原始代码中遇到错误,必须进行一次编辑: headers.Select(column => "\"" + column.HeaderText + "\""); headers.Select(column => "\"" + column.HeaderText + "\"").ToArray(); 我发现了和 BH 一样的东西(并提交了编辑)。除此之外,这是一个很好的答案! 另外,我有一个(单独的)问题,第一列使用了一个特殊的“RowIndex”属性,(奇怪的是)没有设置单元格值。通过抓取“cell.FormattedValue”而不是第一列的 cell.Value 来修复。 sb.AppendLine( string.Join(",", cells.Select( cell => "\"" + (cell.ColumnIndex == 0 ? cell.FormattedValue : cell.Value) + "\"" ).ToArray() )); 使用CurrentCulture.TextInfo.ListSeparator
ì而不是","
如何检查演员表行中的任何单元格是否为空?【参考方案2】:
DataGridView
的一个鲜为人知的功能是能够以编程方式选择部分或全部 DataGridCell,并使用方法 DataGridView.GetClipboardContent()
将它们发送到 DataObject
。那这有什么好处呢?
DataObject
不只是存储一个对象,而是以各种不同格式表示该对象。这就是剪贴板能够发挥其魔力的方式;它存储了各种格式,并且不同的控件/类可以指定他们希望接受的格式。在这种情况下,DataGridView 会将 DataObject 中选定的单元格存储为制表符分隔的文本格式、CSV 格式或 html (*)。
可以通过调用DataObject.GetData()
或DataObject.GetText()
方法并指定预定义的数据格式枚举来检索DataObject 的内容。在这种情况下,我们希望 CSV 的格式为 TextDataFormat.CommaSeparatedValue,然后我们可以使用 System.IO.File
类将该结果写入文件。
(*) 实际上,它返回的并不是严格意义上的 HTML。此格式还将包含您不期望的数据标题。虽然标题确实包含 HTML 的起始位置,但我只是丢弃了 HTML 标记上方的任何内容,例如 myString.Substring(IndexOf("<HTML>"));
。
观察以下代码:
void SaveDataGridViewToCSV(string filename)
// Choose whether to write header. Use EnableWithoutHeaderText instead to omit header.
dataGridView1.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText;
// Select all the cells
dataGridView1.SelectAll();
// Copy selected cells to DataObject
DataObject dataObject = dataGridView1.GetClipboardContent();
// Get the text of the DataObject, and serialize it to a file
File.WriteAllText(filename, dataObject.GetText(TextDataFormat.CommaSeparatedValue));
现在,这不是更好吗?为什么要重新发明***?
希望这会有所帮助...
【讨论】:
我看到这个丑陋的解决方案在网上流传。请不要使用它!首先,SelectionMode = Single
时不起作用。其次,使用剪贴板作为临时存储显然很疯狂。其他一些应用程序可能会干扰和替换对SetDataObject
和GetText
的调用之间的内容。
@l33t 谢谢。你是对的,因为这是一个彻底的黑客攻击,对剪贴板的滥用,绝对不应该在生产代码中依赖。我并没有真正考虑其他应用程序干扰剪贴板的影响,但这是一个有效的担忧。显然有一个 WIN32 API 调用可以锁定剪贴板,但不会在这里命名,因为这会变得更糟,更糟糕的是,完全脱离了疯狂的轨道。尽管回想起来,这段代码对我的需求(原型 POC)有用,但我同意 l33t 的观点,即永远不应该实际使用这种 hack。
目前这似乎是最好的答案,因为.GetClipboardContent
使用单元格格式的值而不是单元格值,并且还可以处理其他答案没有的少数罕见边缘情况,例如包含 @987654334 的值@、"
、\t
、\r
、\n
或当前正在编辑的单元格。对于不想使用.GetClipboardContent
的任何人,我建议寻找处理上述分隔符和转义字符的解决方案。
添加dataGridView1.ClearSelection();最后【参考方案3】:
Please check this code.its working fine
try
//Build the CSV file data as a Comma separated string.
string csv = string.Empty;
//Add the Header row for CSV file.
foreach (DataGridViewColumn column in dataGridView1.Columns)
csv += column.HeaderText + ',';
//Add new line.
csv += "\r\n";
//Adding the Rows
foreach (DataGridViewRow row in dataGridView1.Rows)
foreach (DataGridViewCell cell in row.Cells)
if (cell.Value != null)
//Add the Data rows.
csv += cell.Value.ToString().TrimEnd(',').Replace(",", ";") + ',';
// break;
//Add new line.
csv += "\r\n";
//Exporting to CSV.
string folderPath = "C:\\CSV\\";
if (!Directory.Exists(folderPath))
Directory.CreateDirectory(folderPath);
File.WriteAllText(folderPath + "Invoice.csv", csv);
MessageBox.Show("");
catch
MessageBox.Show("");
【讨论】:
【参考方案4】:发现问题,编码没问题,但我有一个空单元格出现问题。
【讨论】:
!防御性编码!= 很好【参考方案5】:您的代码几乎就在那里......但我做了以下更正,效果很好。谢谢你的帖子。
错误:
string[] output = new string[dgvLista_Apl_Geral.RowCount + 1];
更正:
string[] output = new string[DGV.RowCount + 1];
错误:
System.IO.File.WriteAllLines(filename, output, System.Text.Encoding.UTF8);
更正:
System.IO.File.WriteAllLines(sfd.FileName, output, System.Text.Encoding.UTF8);
【讨论】:
我已经在我的代码中更新了它。我有点懒,只是在这里复制粘贴(直接来自它使用的软件)。【参考方案6】:“csvFileWriter.WriteLine(dataFromGrid);”行应该在右括号下面下移一行,否则你会得到很多重复的结果:
for (int i = 1; i <= countColumn; i++)
dataFromGrid = dataFromGrid + ',' + dataRowObject.Cells[i].Value.ToString();
csvFileWriter.WriteLine(dataFromGrid);
【讨论】:
【参考方案7】:我认为这对您的 SaveToCSV 函数是正确的:(否则为 Null ...)
for (int i = 0; i < columnCount; i++)
不是:
for (int i = 1; (i - 1) < DGV.RowCount; i++)
【讨论】:
以上是关于将datagridview导出到csv文件的主要内容,如果未能解决你的问题,请参考以下文章
如何通过按钮单击将数据导出到 linq c# 中的 .csv 文件