在项目的开发过程中,有数据导出到excel文件的要求,于是就按照正常的思路导出为excel文件。可是在实际使用的过程中发生了许多的问题
由于客户安装的excel的版本的和我开发用到的版本dll不一致,导致好多的导出操作都出现异常,也有部分的客户PC中根本都没有安装office用的是WPS
还有一些其他的因素,由于客户端运行环境的差异,都会出现一些错误。对我来说开发了一个产品而要求使用者必须安装这个那个是一件很不喜欢的事情,
就我来说就很不喜欢使用一个软件时突然出错被告知你需要安装个那个版本的什么东西,会让人很反感。
由此引出万能的csv文件,以前也接触过,知道它的单纯,也懂的它发包容和接纳,于是就想到用csv文件导出。我个人的理解csv文件就和txt文件没有什么区别,只是用起来给人感觉高大上一点点,显得更专业一点,通过将其内容按照一定的规则编辑,既可以按照excel一样按照行列的格式展现。所以csv文件可以用各种版本的excel和WPS打开不会出现任何的兼容的问题,退一万步讲,还可以用记事本打开,可谓海纳百川,有容乃大。
CSV 百度百科:逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)。纯文本意味着该文件是一个字符序列,不含必须像二进制数字那样被解读的数据。CSV文件由任意数目的记录组成,记录间以某种换行符分隔;每条记录由字段组成,字段间的分隔符是其它字符或字符串,最常见的是逗号或制表符。通常,所有记录都有完全相同的字段序列。
就是它了,在系统里边有好多地方都需要将数据导出,所以对于导出的功能我得写成的一个方法,一遍书写,哪里都能用,只需要传递参数即可。
我的设计是将datagridview的数据导出,所以我就想到直接给导出的方法传递一个datagridview的对象,这样只要需要导出的地方只需要将datagridview传递过去即可,
代码如下:
/// <summary>
/// 导出csv文件
/// </summary>
/// <param name="title">导出文件名称</param>
/// <param name="dgv">数据对象</param>
/// <param name="isShowExcel">导出的过程中是否打开正在导出的文件</param>
/// <returns></returns>
public static bool OutToCsvFromDataGridView(string title, DataGridView dgv, bool isShowExcel)
{
if (dgv == null || dgv.RowCount == 0) return true;
SaveFileDialog saveDlg = new SaveFileDialog();
saveDlg.Filter = "CSV文件(*.csv)|*.csv";
saveDlg.FileName = title + DateTime.Now.ToString("yyyyMMddhhmmss");
try
{
if (saveDlg.ShowDialog() == DialogResult.OK)
{
int size = 1024;
int sizeCnt = (int)Math.Ceiling((Double)dgv.RowCount / (Double)2000);
StreamWriter write = new StreamWriter(saveDlg.FileName,false,Encoding.Default,size*sizeCnt);
//标题行
for (int t = 0; t < dgv.ColumnCount; t++)
{
if (dgv.Columns[t].Visible == true)
{
write.Write(dgv.Columns[t].HeaderText + ",");
}
}
write.WriteLine();
//明细行
for (int lin = 2; lin <= dgv.RowCount + 1; lin++)
{
if (dgv.Rows[lin-2].Visible == true)
{
string Tem = "";
for (int k = 0; k < dgv.ColumnCount; k++)
{
if (dgv.Columns[k].Visible == true)
{
if (dgv.Rows[lin - 2].Cells[k].Value != null)
{
string TemString = dgv.Rows[lin - 2].Cells[k].Value.ToString().Trim().Replace(",", ".").Replace("\r\n",".").Replace("\r",".").Replace("\n",".");
Tem += TemString;
Tem += ",";
}
else
{
string TemString = "";
Tem += TemString;
Tem += ",";
}
}
}
write.WriteLine(Tem);
}
}
write.Flush();
write.Close();
CMessageBox.ShowInfoMessage("导出成功:" + saveDlg.FileName.ToString().Trim());
}
}
catch (System.Exception ex)
{
string message = "CSV文件导出失败。" + "\n" + "文件:" + saveDlg.FileName.ToString().Trim() + "\n" + "可能处于打开状态或者被其他程序占用。";
CMessageBox.ShowErrorMessage(message,"确认");
}
return true;
}
这里也将我最初写的导出问excel文件的方法记录下来,说不定哪天万一真的就用上了。
public static bool OutToExcelFromDataGridView(string title, DataGridView dgv, bool isShowExcel)
{
try
{
int titleColumnSpan = 0;//标题的跨列数
string fileName = "";//保存的excel文件名
int columnIndex = 1;//列索引
if (dgv.Rows.Count == 0)
return false;
/*保存对话框*/
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "Excel文档|*.xls;.xls|Excel文档|*.xlsx;.xlsx";//"导出Excel(*.xls)|*.xls";
sfd.FileName = title + DateTime.Now.ToString("yyyyMMddhhmmss");
if (sfd.ShowDialog() == DialogResult.OK)
{
fileName = sfd.FileName;
/*建立Excel对象*/
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
if (excel == null)
{
throw new System.Exception();
}
try
{
excel.Application.Workbooks.Add(true);
excel.Visible = isShowExcel;
#region
/*分析标题的跨列数*/
foreach (DataGridViewColumn column in dgv.Columns)
{
if (column.Visible == true)
titleColumnSpan++;
}
/*合并标题单元格*/
Microsoft.Office.Interop.Excel.Worksheet worksheet = (Microsoft.Office.Interop.Excel.Worksheet)excel.ActiveSheet;
//worksheet.get_Range("A1", "C10").Merge();
worksheet.get_Range(worksheet.Cells[1, 1] as Range, worksheet.Cells[1, titleColumnSpan] as Range).Merge();
/*生成标题*/
excel.Cells[1, 1] = title;
(excel.Cells[1, 1] as Range).HorizontalAlignment = XlHAlign.xlHAlignCenter;//标题居中
//生成字段名称
columnIndex = 1;
for (int i = 1; i < dgv.ColumnCount; i++)
{
if (dgv.Columns[i].Visible == true)
{
excel.Cells[2, columnIndex] = dgv.Columns[i].HeaderText;
(excel.Cells[2, columnIndex] as Range).HorizontalAlignment = XlHAlign.xlHAlignCenter;//字段居中
columnIndex++;
}
}
//填充数据
for (int i = 0; i < dgv.RowCount; i++)
{
columnIndex = 1;
for (int j = 1; j < dgv.ColumnCount; j++)
{
if (dgv.Columns[j].Visible == true)
{
if (dgv[j, i].ValueType == typeof(string))
{
excel.Cells[i + 3, columnIndex] = " " + dgv[j, i].Value.ToString();
}
else
{
excel.Cells[i + 3, columnIndex] = dgv[j, i].Value;
}
(excel.Cells[i + 3, columnIndex] as Range).HorizontalAlignment = XlHAlign.xlHAlignLeft;//字段居左
columnIndex++;
}
}
}
#endregion
worksheet.SaveAs(fileName, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
CMessageBox.ShowInfoMessage("导出成功:" + sfd.FileName.ToString().Trim());
}
catch (System.Exception ex)
{
throw new System.Exception();
}
finally
{
excel.Quit();
excel = null;
GC.Collect();
}
KillProcess("Excel");
return true;
}
}
catch
{
//
}
return true;
}
//杀死与Excel相关的进程
private static void KillProcess(string processName)
{
System.Diagnostics.Process myproc = new System.Diagnostics.Process();//得到所有打开的进程
try
{
foreach (System.Diagnostics.Process thisproc in System.Diagnostics.Process.GetProcessesByName(processName))
{
if (!thisproc.CloseMainWindow())
{
thisproc.Kill();
}
}
}
catch (System.Exception Exc)
{
throw new System.Exception("", Exc);
}
}
其实还想到用WPS导出的但是想到也有版本和没有安装的问题也就放弃了,所以还是选择了最简单但是也最安全的csv,现在运行一年,没有任何的问题,也没有抱怨。
说明我想偷懒也不想要求客户必须装一些东西的出发点也是挺不错的。
说几句闲话,看着很多技术大牛写的博客相当的有技术含量,文采也是相当出色,虽然说的是技术,但读起来却像散文。在下也是相当的仰视的,总觉得自己文采差一点,不敢多写,也觉得我所记录的技术也都过于简单,也不值得一提。
其实后来想想,这所有的胡思乱想都只不过是我的意淫而已,其实记录的不光是技术,也是我的青春,我也就释然了,希望从现在开始自己可以一路坚持,不管难的简单的,只要是自己接触到的统统的记录下来,就算有天青春不在,至少打开这里,也能勾起我的点点回忆,告诉自己,这条路,我也曾经来过。