主題是C#中將數(shù)據(jù)導(dǎo)入到Excel中,其實(shí)方法有很多種,但是應(yīng)用的環(huán)境不同.
廢話少說(shuō),進(jìn)入主題.
首先說(shuō)我的目的,工作需要,我需要做一個(gè)將DataGrid中的數(shù)據(jù)導(dǎo)出到Excel中之后在Excel中編輯完再導(dǎo)回去,同時(shí)更新數(shù)據(jù)庫(kù)的這么一個(gè)功能.
最開(kāi)始的實(shí)現(xiàn)方法很簡(jiǎn)單,在網(wǎng)上找到了一個(gè)例子,仿造寫了以后處理了一點(diǎn)小問(wèn)題以后搞定!點(diǎn)擊按鈕完畢后他可以出現(xiàn)一個(gè)下載的提示框,然后用戶選擇保存路徑,OK,成功導(dǎo)出,速度也很理想,下面是主要代碼,我只寫大概代碼,必要的注釋我都加了:
//記得引用(貫穿全文)using System.Data.OleDb;
//記得引用using System.IO;
//dg為DataGrid的命名
dg.Attributes.Add("style", "vnd.ms-excel numberformat:@"); //此句功能為讓保存的Excel為文本格式,如數(shù)據(jù)中的001 不會(huì)被保存成1,Excel自動(dòng)給00去掉了~沒(méi)辦法誰(shuí)讓他是0呢!
dg.AllowPaging = false;
dg.DataSource = dt; //請(qǐng)自己給DataGrid一個(gè)數(shù)據(jù)源
dg.DataBind();
Response.Clear();
Response.Buffer = true;
Response.Charset = "GB2312";
Response.AppendHeader("Content-Disposition", "attachment;filename=FileName.xls");//FileName是下載時(shí)的名字,當(dāng)然用戶可以自己更改
//設(shè)置輸出流為簡(jiǎn)體中文
Response.ContentEncoding = System.Text.Encoding.GetEncoding("GB2312");
//設(shè)置輸出文件類型為excel文件
Response.ContentType = "application/ms-excel";
this.EnableViewState = false;
System.Globalization.CultureInfo myCItrad = new System.Globalization.CultureInfo("ZH-CN", true);
System.IO.StringWriter oStringWriter = new System.IO.StringWriter(myCItrad);
System.Web.UI.HtmlTextWriter oHtmlTextWriter = new System.Web.UI.HtmlTextWriter(oStringWriter);
dg.RenderControl(oHtmlTextWriter);
Response.Write(oStringWriter.ToString());
Response.End();
///////////////////////////
OK結(jié)束了,就這么簡(jiǎn)單,使用標(biāo)準(zhǔn)輸出流實(shí)現(xiàn)~
如果你只想導(dǎo)出一個(gè)Excel,我想告訴你,OK你的功能實(shí)現(xiàn)了~
But!
如果你像我一樣需要再導(dǎo)回來(lái),我想告訴你~This is not enough~....
導(dǎo)出的Excel你可以右鍵編輯看一下,我靠~ NND居然是一個(gè)偽Excel,他的源文件居然是Html格式的!kao.干~
但是如果你保存一下呢?選擇標(biāo)準(zhǔn)的Excel格式,他就編程了有個(gè)標(biāo)準(zhǔn)的Excel~
所以對(duì)于用戶來(lái)說(shuō)你會(huì)遇到兩種情況,第一個(gè)他很無(wú)聊,是的他很無(wú)聊,導(dǎo)出了,什么都沒(méi)干又導(dǎo)回來(lái)了,我知道,你會(huì)問(wèn)"我kao,這小子不是來(lái)找茬的吧?"是的,我也在心中無(wú)數(shù)次這么罵過(guò)....但是誰(shuí)讓人家是用戶呢!
這樣你面對(duì)的就是一個(gè)Html格式的Excel~如果他編輯后保存再導(dǎo)回去呢,就是一個(gè)標(biāo)準(zhǔn)的Excel文件,當(dāng)然了,作為程序員這兩種情況你都要搞定,OK下面粘一段可以同時(shí)兼容這兩種格式的代碼:
/// <summary>
/// 連接Excel,將Excel里的數(shù)據(jù)轉(zhuǎn)換成DataTable
/// </summary>
/// <param name="filePath">Excel路徑</param>
/// <returns>轉(zhuǎn)換成DataTable以后的Excel內(nèi)容</returns>
public DataTable ImporExcel(string filePath)
{
DataTable ds = new DataTable();
//Excel連接字符串
OleDbConnection conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + filePath + ";Extended Properties=/"Excel 8.0;/"");
//try里為正常數(shù)據(jù)格式 這是針對(duì)標(biāo)準(zhǔn)Excel格式的
try
{
conn.Open();
string fileName = filePath.Substring(filePath.LastIndexOf("http://") + 1); //取得文件名+擴(kuò)展名
fileName = fileName.Substring(0, fileName.IndexOf(".")); //去掉擴(kuò)展名,只剩文件名
OleDbCommand myOleDbCommand = new OleDbCommand("select * from [" + fileName + "$]", conn); //得到表名里的內(nèi)容
OleDbDataAdapter myData = new OleDbDataAdapter(myOleDbCommand);
myData.Fill(ds);
conn.Close();
return ds;
}
//catch里為導(dǎo)入的Excel格式,通過(guò)分析文件,得到一個(gè)ds 這是針對(duì)Html格式的
catch
{
FileStream yuanfile = new FileStream(filePath, FileMode.Open); //當(dāng)然了,如果他導(dǎo)入的是個(gè)圖片...你這里還可以寫try,我只寫大概思路
//打開(kāi)文件
StreamReader tmpStream = new StreamReader(yuanfile, System.Text.Encoding.GetEncoding("utf-8")); //讀出文件,格式為GB2312
string tmpStr = tmpStream.ReadToEnd(); //整個(gè)讀出文件
tmpStream.Close();
ds = GetDataTbaleFromString(tmpStr);
tmpStr = "";
return ds;
}
/// <summary>
/// 將指定Html字符串的數(shù)據(jù)轉(zhuǎn)換成DataTable對(duì)象 --根據(jù)“<tr><td>”等特殊字符進(jìn)行處理
/// </summary>
/// <param name="tmpHtml">Html字符串</param>
/// <returns></returns>
public DataTable GetDataTbaleFromString(string tmpHtml)
{
string tmpStr = tmpHtml;
DataTable dt = new DataTable();
//刪除第一個(gè)<tr>之前合最后一個(gè)</tr>之后的部分
int index = tmpStr.IndexOf("<tr");
if (index > -1)
{
tmpStr = tmpStr.Substring(index);
}
else
{
return dt;
}
index = tmpStr.LastIndexOf("</tr");
if (index > -1)
{
tmpStr = tmpStr.Substring(0, index + 5);
}
else
{
return dt;
}
bool exitsSparator = false;
char Separator = Convert.ToChar("^");
//如果原字符串中包含分隔符“^”則先把它替換掉
if (tmpStr.IndexOf(Separator.ToString()) > -1)
{
exitsSparator = true;
tmpStr = tmpStr.Replace("^", "^$&^");
}
//根據(jù)</tr>分析
string[] tmpRow = tmpStr.Replace("</tr>", "^").Split(Separator); //使用^將字符串分開(kāi)
for (int i = 0; i < tmpRow.Length - 1; i++)
{
DataRow newRow = dt.NewRow();
string tmpStrI = tmpRow[i];
if (tmpStrI.IndexOf("<tr>") > -1)
{
tmpStrI = tmpStrI.Substring(tmpStrI.IndexOf("<tr>"));
if (tmpStrI.IndexOf("display:none") < 0 || tmpStrI.IndexOf("display:none") > tmpStrI.IndexOf(">"))
{
tmpStrI = tmpStrI.Replace("</td>", "^");
string[] tmpField = tmpStrI.Split(Separator);
for (int j = 0; j < tmpField.Length - 1; j++)
{
tmpField[j] = RemoveString(tmpField[j], "<font>");
index = tmpField[j].LastIndexOf(">") + 1;
if (index > 0)
{
string field = tmpField[j].Substring(index, tmpField[j].Length - index);
if (exitsSparator) field = field.Replace("^$&^", "^");
if (i == 0)
{
string tmpFieldName = field;
int sn = 1;
while (dt.Columns.Contains(tmpFieldName))
{
tmpFieldName = field + sn.ToString();
sn += 1;
}
dt.Columns.Add(tmpFieldName);
}
else
{
newRow[j] = field;
}
}//end of if(index>0)
}
if (i > 0)
{
dt.Rows.Add(newRow); //將整理好的DataRow添加到dt里
}
}
}
}
dt.AcceptChanges();
return dt;
}
/// <summary>
/// 從指定Html字符串中剔除指定的對(duì)象
/// </summary>
/// <param name="tmpHtml">Html字符串</param>
/// <param name="remove">需要剔除的對(duì)象--例如輸入<font>則剔除<font ???????>"</font></param>
/// <returns></returns>
public string RemoveString(string tmpHtml, string remove)
{
tmpHtml = tmpHtml.Replace(remove.Replace("<", "</"), ""); //刪除<,</這類字符
tmpHtml = tmpHtml.Replace(" ", ""); //刪除空格字符( ) 你的里面你看看什么是多于的,你就刪什么,別客氣,千萬(wàn)別給我留面子!
tmpHtml = RemoveStringHead(tmpHtml, remove);
return tmpHtml;
}
/// <summary>
/// 只供方法RemoveString()使用
/// </summary>
/// <param name="tmpHtml"></param>
/// <param name="remove"></param>
/// <returns>處理好的字符串</returns>
private string RemoveStringHead(string tmpHtml, string remove)
{
//為了方便注釋,假設(shè)輸入?yún)?shù)remove="<font>"
if (remove.Length < 1)
{
return tmpHtml;//參數(shù)remove為空:不處理返回
}
if ((remove.Substring(0, 1) != "<" || remove.Substring(remove.Length - 1) != ">"))
{
return tmpHtml;//參數(shù)remove不是<?????>:不處理返回
}
int IndexS = tmpHtml.IndexOf(remove.Replace(">", ""));//查找“<font”的位置
int IndexE = -1;
if (IndexS > -1)
{
string tmpRight = tmpHtml.Substring(IndexS, tmpHtml.Length - IndexS);
IndexE = tmpRight.IndexOf(">");
if (IndexE > -1)
{
tmpHtml = tmpHtml.Substring(0, IndexS) + tmpHtml.Substring(IndexS + IndexE + 1);
}
if (tmpHtml.IndexOf(remove.Replace(">", "")) > -1)
{
tmpHtml = RemoveStringHead(tmpHtml, remove);
}
}
return tmpHtml;
}
///////////////////////
OK,結(jié)束,后兩個(gè)類是針對(duì)第一個(gè)的實(shí)現(xiàn)方法,也就是Html的導(dǎo)入,因?yàn)樗荋tml格式,所以他不能用一個(gè)方法直接讀取進(jìn)來(lái),但是他畢竟是有規(guī)律的Html文件,找到規(guī)律,循環(huán)一下,處理一下就出來(lái)了!
OK到此,導(dǎo)入導(dǎo)出全部OK了!
我再往下寫呢,可能真正仔細(xì)看這篇文章的,并且和我一樣也遇到了這個(gè)問(wèn)題的而且依然沒(méi)有解決來(lái)尋找答案的朋友可能要給我扔板磚了....
long totalCount = dt.Rows.Count; //dt的行數(shù),一會(huì)循環(huán)要用
//FileName為路徑(注意名字要和表的名字一樣,比如在次方法中應(yīng)為excel,其實(shí)這3個(gè)參數(shù)應(yīng)該全用變量代替的,呵呵,自己寫吧,我不改了)
string connString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + FileName+ ";Extended roperties=Excel 8.0;";
OleDbConnection objConn = new OleDbConnection(connString);
OleDbCommand objCmd = new OleDbCommand();
objCmd.Connection = objConn;
objConn.Open();
//創(chuàng)建表的結(jié)構(gòu)
objCmd.CommandText = "CREATE TABLE excel(ID int ,字段 varchar)";
objCmd.ExecuteNonQuery();
//插入表
for (int i = 0; i < dt.Rows.Count; i++)
{
objCmd.CommandText = "INSERT INTO excel(ID,字段) values"
+ "('" + dt.Rows[i][0].ToString() + "','" + dt.Rows[i][1].ToString() + "')";
objCmd.ExecuteNonQuery();
}
objConn.Close();
/////////////////////////
請(qǐng)看上段代碼....創(chuàng)建一個(gè)標(biāo)準(zhǔn)Excel,代碼你也可以繼續(xù)擴(kuò)展,比如說(shuō)讓用戶自己選擇路徑啊什么的,等等一系列吧,強(qiáng)調(diào)一下,這個(gè)方法貌似解決了Excel進(jìn)程沒(méi)有關(guān)閉的問(wèn)題!無(wú)需引用Excel組件,無(wú)需繁瑣的代碼,謝謝!
啊?導(dǎo)入?就用剛才上面那段標(biāo)準(zhǔn)Excel的就OK了~
還有就是web呢,這個(gè)導(dǎo)出是在服務(wù)器上的,你再給個(gè)超鏈接讓用戶下載就OK了.
再次強(qiáng)調(diào)!部分代碼來(lái)源于網(wǎng)絡(luò),本人做了一下整理和處理,目的是為了適應(yīng)自己的程序,在此我只寫了一個(gè)大概思路,千萬(wàn)別粘進(jìn)去就用啊~ 保證你死翹翹~~~!!!