c#中winform方式的檔案上傳和下載高效最新方法
網上很多檔案上傳下載的文章,多數是採用http方式,使用.net的webcliend的功能,此功能對大檔案效率比較低,對web伺服器安全性也有影響。
我採用資料庫的方式同樣實現並高效的處理了此功能,對於資料庫winform應用值得借鑑。
開發思路(以下思路是c/s三層架構,中間需要有webservice服務):
1 把資料存於資料庫也可以不存入資料庫,如果存入資料庫就要在表中增加image欄位存放byte資料。
2 採filestream對像,對檔案進行讀寫操作,不管是存入資料庫還是以檔案形式上傳到伺服器的檔案系統中
上傳部分選擇檔案都是相同的,都需要用到資料表,如果要存入資料庫就要建表,如果不存入資料庫可以
用sql語句虛擬一個表結構:如Select file_Id=0,file_name='',convert(image,null) file_data where 1<>1
3 如果是把檔案存入web伺服器,在webservice中需要有上傳和下載的函式。上傳時就是把dataset中的byte還原
成檔案流fileStream,再把檔案寫入檔案系統(此方式要設定iis對檔案系統的寫的許可權,不然會提示拒絕訪問);
下載就是根據檔名用fileStream把檔案從檔案系統中讀取來,再以byte的形式放入dataset.table中。
4 檔案的另存,檔案的另存把datatabel中的byte寫入filestream中,再寫入客戶端的檔案系統中。
以下是開發的全程式碼:
1 此段是用檔案開啟控制元件選擇檔案,把檔案寫入table的對應的路徑中。
2 下面是把table中的檔案流另存到客戶端檔案private void btnBrowse_Click(object sender, EventArgs e) { OpenFileDialog filedlg = new OpenFileDialog(); filedlg.Multiselect = true; if (filedlg.ShowDialog() == DialogResult.OK) { string[] filenames = filedlg.FileNames; for (int i = 0; i < filenames.Length; i++) { string fileName = filenames[i]; int n = fileName.LastIndexOf(@"\"); string file = fileName.Substring(n + 1, fileName.Length - n - 1); sDH=dgvMSG.CurrentRow.Cells["MSG_DH"].Value.ToString(); if (File.Exists(fileName)) { DataRow[] dr1=dsMSG .Tables ["MSG_DOC"].Select ("MSGDOC_DH='"+sDH +"' AND MSGDOC_FILENAME='"+file +"'"); if (dr1.Length <=0) { DataRow dr = dsMSG.Tables["MSG_DOC"].NewRow(); dr["MSGDOC_DH"] = sDH; dr["MSGDOC_FILENAME"] = file; FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); byte[] bt = new byte[fs.Length]; fs.Position = 0; fs.Read(bt, 0, Convert.ToInt32(fs.Length)); dr["MSGDOC_FILE"] = bt; dsMSG.Tables["MSG_DOC"].Rows.Add(dr); lbFILES.Items.Add(file); } } } btnSAVEAS.Enabled = (lbFILES.Items.Count > 0); } }
private void btnSAVEAS_Click(object sender, EventArgs e)
{
if (lbFILES.SelectedItems.Count > 0 && dgvMSG .Rows .Count >0)
{
string sDH = dgvMSG.CurrentRow.Cells["MSG_DH"].Value.ToString();
FolderBrowserDialog fld = new FolderBrowserDialog();
if (fld.ShowDialog ()== DialogResult.OK)
{
waiting w = new waiting();
try
{
w.Show();
DataSet dsMSG_DOC = Query_MSG_DOC(sDH);
string path = fld.SelectedPath;
if (!path.EndsWith(@"\"))//判斷是否為根目錄,如果不是根目錄要新增分隔符"\"
path += @"\";
for (int i = 0; i < lbFILES.SelectedItems.Count; i++)
{
string sFilename = lbFILES.SelectedItems[i].ToString();
DataRow[] dr = dsMSG_DOC.Tables["MSG_DOC"].Select("MSGDOC_DH='" + sDH + "' AND MSGDOC_FILENAME='" + sFilename + "'");
if (dr.Length > 0 && dr[0]["MSGDOC_FILE"] != null)
{
byte[] btFile = (byte[])dr[0]["MSGDOC_FILE"];
FileStream fs = new FileStream(path + sFilename, FileMode.Create);
fs.Write(btFile, 0, btFile.Length);
fs.Close();
}
}
}
finally
{
w.Close();
}
}
}
}
3 下面是如何移除檔案列表和資料表中的資料
private void btnRemove_Click(object sender, EventArgs e)
{
if (!isinBrowse)
{
for (int i = 0; i < lbFILES.SelectedItems.Count; i++)
{
string filename = lbFILES.SelectedItems[i].ToString();
string sDH = dgvMSG.CurrentRow.Cells["MSG_DH"].Value.ToString();
DataRow[] dr = dsMSG.Tables["MSG_DOC"].Select("MSGDOC_DH='" + sDH + "' AND MSGDOC_FILENAME='" + filename + "'");
if (dr.Length > 0)
{
string sID=Convert.ToString (dr[0]["MSGDOC_ID"]);
dsMSG.Tables["MSG_DOC"].Rows.Remove(dr[0]);
string sql = "Delete FROM MSG_DOC WHERE MSGDOC_DH='" + sDH + "'"
+ " AND MSGDOC_ID=" + sID ;
string msgError = "";
POS.SQLcmd_1(BASEINFO.DESEncrypt(sql), Program.userinfo.P_user.U_ID.ToString(), out msgError);
//lbFILES.Items.Remove(lbFILES.SelectedItems[i]);
}
}
object[] selected_objs = new object[lbFILES.SelectedItems.Count];
lbFILES.SelectedItems.CopyTo(selected_objs, 0);
foreach (object oval in selected_objs)
{
lbFILES.Items.Remove(oval);
}
SetToolsBtn();
}
}
4 下面webserve把檔案流存入伺服器的檔案系統中
[WebMethod]
public bool UplodeFiles(byte[] btData, out string errorMsg)
{
try
{
DataSet dsFILE = serverbase.DecompressDS(btData);
DataRow drs = dsFILE.Tables[0].Rows[0];
byte []btFile=(byte[])dsFILE.Tables[0].Rows[0]["FILE_DATA"];
string fileName = Convert.ToString (dsFILE.Tables[0].Rows[0]["FILENAME"]);
FileStream fs = new FileStream(@"D:\" + fileName,FileMode.CreateNew); \\此處為了測試方便用的固定路徑,業務上可以通過引數傳路徑
fs.Write(btFile, 0, btFile.Length);
fs.Close();
errorMsg = "";
return true;
}
catch (Exception E)
{
errorMsg = E.Message.ToString();
return false;
}
finally
{
}
}
5 如果只是存入伺服器的檔案系統,在第1段程式碼後面,呼叫webserve的上傳函式就可以了。
增下下面程式碼 你的webservice.UplodeFiles(BASEINFO.SerializationDataset(dsFILE), out msgError);
6下載檔案伺服器檔案到客戶端就是反過來就好了。
7直接雙擊檔案列表開啟檔案方法如下:
private void lbFILES_DoubleClick(object sender, EventArgs e)
{
if (isinBrowse && lbFILES.Items.Count > 0 && dgvMSG.Rows.Count > 0)
{
string sDH = dgvMSG.CurrentRow.Cells["MSG_DH"].Value.ToString();
DataSet dsMSG_DOC = Query_MSG_DOC(sDH);
string path = System.IO.Path.GetTempPath();//Environment.GetEnvironmentVariable("TEMP");
if (!path.EndsWith(@"\"))//判斷是否為根目錄,如果不是根目錄要新增分隔符"\"
path += @"\";
string sFilename = lbFILES.Items[lbFILES.SelectedIndex].ToString ();
DataRow[] dr = dsMSG_DOC.Tables["MSG_DOC"].Select("MSGDOC_DH='" + sDH + "' AND MSGDOC_FILENAME='" + sFilename + "'");
if (dr.Length > 0 && dr[0]["MSGDOC_FILE"] != null)
{
byte[] btFile = (byte[])dr[0]["MSGDOC_FILE"];
FileStream fs = new FileStream(path + sFilename, FileMode.Create);
fs.Write(btFile, 0, btFile.Length);
System.Diagnostics.Process.Start(path + sFilename);
fs.Close();
}
}
}