C# 由Datatable导出Excel遇到的问题

Ceebic008 2019-07-10 05:19:54
本人新手小白,由于工作需要,遇到c#从数据库中导出到Excel,在网上查阅了好多文件和代码,已经可以实现导出,但是遇到一个问题,每次运行程序并无异常,但是电脑重新启动时会默认打开一个空的Excel。
下面贴出代码,请各位大神帮忙指导一下,问题出在哪里!
// 此代码摘抄自网上,感谢网上大神分享的方法
//快速转excel的方法
public static bool SuperToExcel(DataTable excelTable, string filename,string filePath)
{
Excel.Application app =new Excel.Application();
try
{
app.Visible = false;
Excel.Workbook wBook = app.Workbooks.Add(true);
Excel.Worksheet wSheet = wBook.Sheets[1];
wSheet.Name = filename;
object[,] objData = new object[excelTable.Rows.Count + 1, excelTable.Columns.Count];
//首先将数据写入到一个二维数组中
for (int i = 0; i < excelTable.Columns.Count; i++)
{
objData[0, i] = excelTable.Columns[i].ColumnName;
}
if (excelTable.Rows.Count > 0)
{
for (int i = 0; i < excelTable.Rows.Count; i++)
{
for (int j = 0; j < excelTable.Columns.Count; j++)
{
if (excelTable.Rows[i][j].Equals(float.NaN))//查询过来的float.NaN
objData[i + 1, j] = "-";
//else if (String.IsNullOrEmpty(excelTable.Rows[i][j].ToString()) && excelTable.Rows[i][j].Equals(DBNull.Value))//有dbnull的数据,需要屏蔽掉——在数据源处理了
// objData[i + 1, j] = excelTable.Rows[i][j];
else
objData[i + 1, j] = excelTable.Rows[i][j];
}
}
}
string startCol = "A";//这里关键,计算要替换的区域
int iCnt = ((excelTable.Columns.Count - 1) / 26);//当列数是26时 不-1 会出现问题,自己试试就明白了
string endColSignal = (iCnt == 0 ? "" : ((char)('A' + (iCnt - 1))).ToString());
string endCol = endColSignal + ((char)('A' + excelTable.Columns.Count - iCnt * 26 - 1)).ToString();
Microsoft.Office.Interop.Excel.Range range = wSheet.get_Range(startCol + "1", endCol + (excelTable.Rows.Count + 1).ToString());
range.Value = objData; //给Exccel中的Range整体赋值
range.EntireColumn.AutoFit(); //设定Excel列宽度自适应
wSheet.get_Range(startCol + "1", endCol + "1").Font.Bold = 1;//Excel文件列名 字体设定为Bold
//设置禁止弹出保存和覆盖的询问提示框
app.DisplayAlerts = false;
app.AlertBeforeOverwriting = false;
//保存工作簿
//wBook.Save();
wSheet.SaveAs(filePath);
wBook.Close();
//保存excel文件
//app.Save(filePath);
//app.SaveWorkspace(filePath);
app.Quit();
GC.Collect();
return true;
}
catch (Exception err)//这里还有些问题,比如 对方安装的是WPS 不会提示中文错误,没有安装office 也不会弹出该错误
{
MessageBox.Show("导出Excel出错!错误原因:" + err.Message, "提示信息",MessageBoxButtons.OK, MessageBoxIcon.Information);
return false;
}
}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
调用执行程序如下:
//创建datatable
DataTable dt = new DataTable("NewDt");
//创建自增长的ID列
DataColumn dc = dt.Columns.Add("ID", Type.GetType("System.Int32"));
dc.AutoIncrement = true; //自动增加
dc.AutoIncrementSeed = 1; //起始为1
dc.AutoIncrementStep = 1; //步长为1
dc.AllowDBNull = false; //非空
//创建其它列表
dt.Columns.Add(new DataColumn("Name", Type.GetType("System.String")));
dt.Columns.Add(new DataColumn("Age", Type.GetType("System.Int32")));
dt.Columns.Add(new DataColumn("Score", Type.GetType("System.Decimal")));
dt.Columns.Add(new DataColumn("CreateTime", Type.GetType("System.DateTime")));
//创建数据
DataRow dr = dt.NewRow();
dr["Name"] = "张三";
dr["Age"] = 28;
dr["Score"] = 85.5;
dr["CreateTime"] = DateTime.Now;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["Name"] = "李四";
dr["Age"] = 24;
dr["Score"] = 72;
dr["CreateTime"] = DateTime.Now;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["Name"] = "王五";
dr["Age"] = 36;
dr["Score"] = 63.5;
dr["CreateTime"] = DateTime.Now;
dt.Rows.Add(dr);
string fullPath = "";
SaveFileDialog dialog = new SaveFileDialog
{Filter = "Excel文件(*.xlsx)|*.xlsx"//设置对话框保存的文件类型,可以设置为 dialog.Filter = "Excel文件(*.xlsx)|*.xlsx"};
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)//将ok返回默认用户公共对话框
{
fullPath = dialog.FileName;//获取文件路径和文件名
}
if (fullPath != "")
{
FileInfo fi = new FileInfo(fullPath);//创建名xlsx文件
fi.Directory.Create();
}
if (SuperToExcel(dt, "a", fullPath))
{
MessageBox.Show("导出成功");
}
else
{
MessageBox.Show("导出失败");
}
...全文
2082 23 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
道斯 2019-07-15
  • 打赏
  • 举报
回复
用npoi吧,不会出这个错误的。进程这东西后期存在问题,“假死”就够你受的。
NE1620_ 2019-07-13
  • 打赏
  • 举报
回复
将DataTable dt=new DataTable声明为全局变量试试
lionheart922 2019-07-12
  • 打赏
  • 举报
回复
不要用office com了,效率低下,又容易泄露内存,推荐使用开源软件closeXml,nuget上应该就有
yolinsa 2019-07-12
  • 打赏
  • 举报
回复
来看看大神大神
Ceebic008 2019-07-12
  • 打赏
  • 举报
回复
https://blog.csdn.net/spw55381155/article/details/79891108
有遇到类似问题的新手兄弟,可以参考上面网址的解决办法
Ceebic008 2019-07-12
  • 打赏
  • 举报
回复
引用 14 楼 XBodhi. 的回复:
CSV 就是 EXCEL 的一种格式之一,你用 EXCEL 只是个工具他可以打开很多格式的,最后呈现的方式还是 EXCEL 的样子。而且方便 兼容性比较好 CSV 。

哦,不好意思,我刚在结帖子,昨天看到有人说可以导成csv格式,我昨天查了一下csv格式转化到excel,发现打开后还需要进行转存操作,这样的话对于用户来说操纵体验并不好,所以没有采用
XBodhi. 2019-07-12
  • 打赏
  • 举报
回复
CSV 就是 EXCEL 的一种格式之一,你用 EXCEL 只是个工具他可以打开很多格式的,最后呈现的方式还是 EXCEL 的样子。而且方便 兼容性比较好 CSV 。
Ceebic008 2019-07-12
  • 打赏
  • 举报
回复
多谢各位大佬,在网上找到了方法,确实如9楼所说,是GC.Collect();出的问题,重新关闭对应进程就好
大鱼> 2019-07-12
  • 打赏
  • 举报
回复
NPOI给你封装好了,看你写的代码头都大
Ceebic008 2019-07-12
  • 打赏
  • 举报
回复
引用 4 楼 XBodhi. 的回复:
如果你只导出数据,不设置样式的话,推荐你 导出 CSV 格式。

可以参考
代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ExportAlarmDataToExcel
{
public partial class Form1 : Form
{
private static readonly SqlConnection sqlConnection = new SqlConnection();
private DataTable tBSystemAlarm = null;
private bool isExporting = false;
public Form1()
{
InitializeComponent();
this.FormClosed += (s, e) =>
{
sqlConnection.Close();
};
}

/// <summary>
/// 登陆数据库
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnLoginDB_Click(object sender, EventArgs e)
{
if (sqlConnection.State == ConnectionState.Open)
{
return;
}
string dataSource = txtIP.Text.Trim();
string userId = txtUserName.Text.Trim();
string password = txtPassword.Text.Trim();
if (string.IsNullOrEmpty(dataSource))
{
return;
}
if (string.IsNullOrEmpty(userId))
{
return;
}

if (string.IsNullOrEmpty(password))
{
return;
}

if (Open(dataSource, userId, password))
{
tBSystemAlarm = new DataTable();
try
{
FillData(tBSystemAlarm);
int count = tBSystemAlarm.Rows.Count;
txtLog.Text += $"时间:{DateTime.Now} => 获取数据成功,总共包含到 {count} 条记录!\r\n";
if (count > 0)
this.btnExport.Visible = true;
}
catch (Exception ex)
{
txtLog.Text += $"时间:{DateTime.Now} => 获取数据异常,请联系管理员!\r\n";
}
}
}
/// <summary>
/// 获取数据表 TB_System_Alarm 的全部信息
/// </summary>
/// <returns></returns>
private void FillData(DataTable tBSystemAlarm)
{
SqlCommand sqlCommand = new SqlCommand("SELECT CreateTime,DeviceId,ChannelId,AlarmLevel,AlarmTypeName,Possibility,Center,Longitude,Latitude,Width,CreateDate,Stadus,Timestamp,Remark,Display,Discribe FROM TB_System_Alarm");
sqlCommand.Connection = sqlConnection;
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlCommand);
sqlDataAdapter.Fill(tBSystemAlarm);
}

private void ExportToExcel()
{
Thread thread = new Thread(new ThreadStart(() =>
{
using (StreamWriter sw = new StreamWriter(File.Create(this.saveFileDialog1.FileName), Encoding.UTF8))
{
StringBuilder csvHeader = new StringBuilder();

for (int h = 0; h < this.tBSystemAlarm.Columns.Count; h++)
{
csvHeader.Append(',');
csvHeader.Append(this.tBSystemAlarm.Columns[h].Caption);
}
sw.WriteLine(csvHeader);
for (int r = 0; r < this.tBSystemAlarm.Rows.Count; r++)
{
StringBuilder csvBody = new StringBuilder();
DataRow row = this.tBSystemAlarm.Rows[r];
for (int c = 0; c < this.tBSystemAlarm.Columns.Count; c++)
{
csvBody.Append(',');
csvBody.Append(row[c]);
}
sw.WriteLine(csvBody);
SetProcess($"已导出 {r + 1} 条警报数据!");
}
}
SetProcess("已全部导出!");
}));
thread.Start();
}

private void SetProcess(string messageText)
{
if (this.InvokeRequired)
{
this.Invoke(new Action(() =>
{
this.btnExport.Text = messageText;
}));
}
else
{
this.btnExport.Text = messageText;
}
}

private bool Open(string dataSource, string userId, string password)
{
sqlConnection.ConnectionString = $"Data Source={dataSource};Initial Catalog=monitoring;User Id={userId};Password={password}";
try
{
sqlConnection.Open();
return true;
}
catch (Exception ex)
{
MessageBox.Show("数据库链接错误,请确认您输入的信息是否正确,并且检查网络是否配置正常,数据库远程服务是否启动!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}

private void btnExport_Click(object sender, EventArgs e)
{
this.btnExport.Enabled = false;
//this.saveFileDialog1.Filter = "(*.xls)|*.xls|(*.xlsx)|*.xlsx";
this.saveFileDialog1.Filter = "(*.csv)|*.csv";
string fileName = this.saveFileDialog1.FileName;
this.saveFileDialog1.ShowDialog();
ExportToExcel();
}
}
}


多谢,主要是考虑到导出excel查看比较方便,而且格式比较好定制
Ceebic008 2019-07-12
  • 打赏
  • 举报
回复



引用 9 楼 lxjwxy 的回复:
是不是excel进程残留。

app.Quit();
GC.Collect();
只这样是不行的

那请问应该如何结束?请指教!
我结束程序之后看过,进程里没有excel,而且我看好多都是这么结束的
XBodhi. 2019-07-12
  • 打赏
  • 举报
回复
获取进程ID kill掉
Ceebic008 2019-07-12
  • 打赏
  • 举报
回复
引用 19 楼 XBodhi. 的回复:
[quote=引用 16 楼 Ceebic 的回复:]
https://blog.csdn.net/spw55381155/article/details/79891108
有遇到类似问题的新手兄弟,可以参考上面网址的解决办法


这个是找到了 进程 ID ,然后 KILL 的。[/quote]
嗯,这样应该就解决了弹出的问题,因为本来我做的代码已经能够正常运转了,只是GC.Collect();方法在关闭进程时不能完全关闭
XBodhi. 2019-07-12
  • 打赏
  • 举报
回复
引用 16 楼 Ceebic 的回复:
https://blog.csdn.net/spw55381155/article/details/79891108
有遇到类似问题的新手兄弟,可以参考上面网址的解决办法


这个是找到了 进程 ID ,然后 KILL 的。
9527-早 2019-07-11
  • 打赏
  • 举报
回复
你可以使用NPOI库进行导出导入操作,很方便。如果需要库私我给你下载链接。
一个武术猴子 2019-07-11
  • 打赏
  • 举报
回复
每次 重启电脑就打开一个空的excel表格???还是?点击的时候第一次出现了空的excel表格?代码有点多。。。可能看的不仔细、、你可以打断点调试下。。。我看了看也没用说 给excel传输 datable null的情况。。。。要打断点看看。。。F12进去调试。。。
lxjwxy 2019-07-11
  • 打赏
  • 举报
回复
是不是excel进程残留。

app.Quit();
GC.Collect();
只这样是不行的
  • 打赏
  • 举报
回复
现在回复怎么这样改了?表示不解
  • 打赏
  • 举报
回复
Ceebic008 2019-07-11
  • 打赏
  • 举报
回复
引用 2 楼 一个武小猴子 的回复:
每次 重启电脑就打开一个空的excel表格???还是?点击的时候第一次出现了空的excel表格?代码有点多。。。可能看的不仔细、、你可以打断点调试下。。。我看了看也没用说 给excel传输 datable null的情况。。。。要打断点看看。。。F12进去调试。。。

可能我没说太清。是程序运行可以正常生成Excel,不是空的,没有任何问题。但是下次电脑重新开机后会自动加载并打开一个空的excel文件,如果此时关闭这个空excel后,以后再重启电脑也不会出现空的excel。但是只要通过这个程序建立excel,再次重启就会出现空excel
加载更多回复(3)

111,094

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧