轉(zhuǎn):http://www.cnblogs.com/7in10/archive/2008/05/20/1203402.html
方案一:
注意:要開啟虛擬目錄的“寫入”權(quán)限,要不然就報(bào) 403 錯(cuò)誤
工作中用到winform上傳文件(-_-!,很少用winform,搞了半天)
碰到一點(diǎn)問題,解決如下
1、501 為實(shí)現(xiàn)錯(cuò)誤
解決方法:
先把IISWEB服務(wù)擴(kuò)展中的WebDev打開
然后
IIS站點(diǎn)添加MIME txt類型常見的MIME類型如下
超文本標(biāo)記語言文本 .html,.html text/html
普通文本 .txt text/plain
RTF文本 .rtf application/rtf
GIF圖形 .gif image/gif
JPEG圖形 .ipeg,.jpg image/jpeg
au聲音文件 .au audio/basic
MIDI音樂文件 mid,.midiaudio/midi,audio/x-midi
RealAudio音樂文件 .ra, .ram audio/x-pn-realaudio
MPEG文件 .mpg,.mpeg video/mpeg
AVI文件 .avi video/x-msvideo
GZIP文件 .gz application/x-gzip
TAR文件 .tar application/x-tar
再然后
設(shè)置目標(biāo)文件夾的可寫性
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
namespace Common
{
///<summary>
/// winform形式的文件傳輸類
///</summary>
publicclass WinFileTransporter
{
///<summary>
/// WebClient上傳文件至服務(wù)器,默認(rèn)不自動(dòng)改名
///</summary>
///<param name="fileNamePath">文件名,全路徑格式</param>
///<param name="uriString">服務(wù)器文件夾路徑</param>
publicvoid UpLoadFile(string fileNamePath, string uriString)
{
UpLoadFile(fileNamePath, uriString, false);
}
///<summary>
/// WebClient上傳文件至服務(wù)器
///</summary>
///<param name="fileNamePath">文件名,全路徑格式</param>
///<param name="uriString">服務(wù)器文件夾路徑</param>
///<param name="IsAutoRename">是否自動(dòng)按照時(shí)間重命名</param>
publicvoid UpLoadFile(string fileNamePath, string uriString, bool IsAutoRename)
{
string fileName = fileNamePath.Substring(fileNamePath.LastIndexOf("\\") + 1);
string NewFileName = fileName;
if (IsAutoRename)
{
NewFileName = DateTime.Now.ToString("yyMMddhhmmss") + DateTime.Now.Millisecond.ToString() + fileNamePath.Substring(fileNamePath.LastIndexOf("."));
}
string fileNameExt = fileName.Substring(fileName.LastIndexOf(".") + 1);
if (uriString.EndsWith("/") == false) uriString = uriString + "/";
uriString = uriString + NewFileName;
Utility.LogWriter log = new Utility.LogWriter();
//log.AddLog(uriString, "Log");
//log.AddLog(fileNamePath, "Log");
/**/
///創(chuàng)建WebClient實(shí)例
WebClient myWebClient = new WebClient();
myWebClient.Credentials = CredentialCache.DefaultCredentials;
// 要上傳的文件
FileStream fs = new FileStream(fileNamePath, FileMode.Open, FileAccess.Read);
//FileStream fs = OpenFile();
BinaryReader r = new BinaryReader(fs);
byte[] postArray = r.ReadBytes((int)fs.Length);
Stream postStream = myWebClient.OpenWrite(uriString, "PUT");
try
{
//使用UploadFile方法可以用下面的格式
//myWebClient.UploadFile(uriString,"PUT",fileNamePath);
if (postStream.CanWrite)
{
postStream.Write(postArray, 0, postArray.Length);
postStream.Close();
fs.Dispose();
log.AddLog("上傳日志文件成功!", "Log");
}
else
{
postStream.Close();
fs.Dispose();
log.AddLog("上傳日志文件失敗,文件不可寫!", "Log");
}
}
catch (Exception err)
{
postStream.Close();
fs.Dispose();
//Utility.LogWriter log = new Utility.LogWriter();
log.AddLog(err, "上傳日志文件異常!", "Log");
throw err;
}
finally
{
postStream.Close();
fs.Dispose();
}
}
/**/
///<summary>
///下載服務(wù)器文件至客戶端
///</summary>
///<param name="URL">被下載的文件地址,絕對(duì)路徑</param>
///<param name="Dir">另存放的目錄</param>
publicvoid Download(string URL, string Dir)
{
WebClient client = new WebClient();
string fileName = URL.Substring(URL.LastIndexOf("\\") + 1); //被下載的文件名
string Path = Dir + fileName; //另存為的絕對(duì)路徑+文件名
Utility.LogWriter log = new Utility.LogWriter();
try
{
WebRequest myre = WebRequest.Create(URL);
}
catch (Exception err)
{
//MessageBox.Show(exp.Message,"Error");
log.AddLog(err, "下載日志文件異常!", "Log");
}
try
{
client.DownloadFile(URL, fileName);
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
BinaryReader r = new BinaryReader(fs);
byte[] mbyte = r.ReadBytes((int)fs.Length);
FileStream fstr = new FileStream(Path, FileMode.OpenOrCreate, FileAccess.Write);
fstr.Write(mbyte, 0, (int)fs.Length);
fstr.Close();
}
catch (Exception err)
{
//MessageBox.Show(exp.Message,"Error");
log.AddLog(err, "下載日志文件異常!", "Log");
}
}
}
}
方案二:
轉(zhuǎn):http://blog.csdn.net/walkinhill/archive/2004/08/28/87656.aspx
相信用ASP.NET寫一個(gè)上傳文件的網(wǎng)頁,大家都會(huì)寫,但是有沒有人想過通過在WinForm中通過HTTP協(xié)議上傳文件呢?
有些人說要向服務(wù)器端上傳文件,用FTP協(xié)議不是很簡(jiǎn)單嗎?效率又高,為什么還要使用HTTP協(xié)議那么麻煩呢?這里面有幾個(gè)原因:
(1)FTP服務(wù)器的部署相對(duì)麻煩,還要設(shè)置權(quán)限,權(quán)限設(shè)置不對(duì),還會(huì)惹來一系列的安全問題。
(2)如果雙方都還有防火墻,又不想開發(fā)FTP相關(guān)的一些端口時(shí),HTTP就會(huì)大派用場(chǎng),就像WEB Services能穿透防火墻一樣。
(3)其他的...,還在想呢...
但是使用HTTP也有他的一些問題,例如不能斷點(diǎn)續(xù)傳,大文件上傳很難,速度很慢,所以HTTP協(xié)議上傳的文件大小不應(yīng)該太大。
說了這么多,原歸正傳,一般來說,在Winform里通過HTTP上傳文件有幾種可選的方法:
(1)前面提到的Web Services,就是一種很好的方法,通過編寫一個(gè)WebMethod,包含有 byte[] 類型的參數(shù),然后調(diào)用Web Services的方法,文件內(nèi)容就會(huì)以Base64編碼傳到服務(wù)器上,然后重新保存即可。
[WebMethod]
public void UploadFile(byte[] content,string filename){
Stream sw = newStreamWriter(...);
sw.Close();
}
當(dāng)然,這種通過Base64編碼的方法效率比較低,那么可以采用WSE,支持附件,并以2進(jìn)制形式傳送,效率會(huì)更高。
(2)除了通過WebService,另外一種更簡(jiǎn)單的方法就是通過WebClient或者HttpWebRequest來模擬HTTP的POST動(dòng)作來實(shí)現(xiàn)。這時(shí)候首先需要編寫一個(gè)asp.net web form來響應(yīng)上傳,代碼如下:
<%@ Page language="c#" Codebehind="WebForm1.aspx.cs"AutoEventWireup="false" Inherits="UploadFileWeb.WebForm1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html>
<head>
<title>WebForm1</title>
<meta name="GENERATOR" Content="Microsoft VisualStudio .NET 7.1">
<meta name="CODE_LANGUAGE" Content="C#">
<meta name="vs_defaultClientScript"content="JavaScript">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
</head>
<body>
<form id="Form1" method="post"runat="server">
</form>
</body>
</html>
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespaceUploadFileWeb
{
/// <summary>
/// WebForm1 的摘要說明。
/// </summary>
public class WebForm1 : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
// 在此處放置用戶代碼以初始化頁面
foreach( string f in Request.Files.AllKeys)
{
HttpPostedFile file = Request.Files[f];
file.SaveAs(@"D:\Temp\" + file.FileName);
}
if( Request.Params["testKey"] != null )
{
Response.Write(Request.Params["testKey"]);
}
}
#regionWeb 窗體設(shè)計(jì)器生成的代碼
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: 該調(diào)用是 ASP.NET Web 窗體設(shè)計(jì)器所必需的。
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// 設(shè)計(jì)器支持所需的方法 -不要使用代碼編輯器修改
/// 此方法的內(nèi)容。
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
}
}
其實(shí)這個(gè)頁面跟我們平常寫的asp.net上傳文件代碼是一樣的,在Web 頁的Request對(duì)象中包含有Files這個(gè)對(duì)象,里面就包含了通過POST方式上傳的所有文件的信息,這時(shí)所需要做的就是調(diào)用Request.Files[i].SaveAs方法。
但是怎么讓才能在WinForm里面模擬想Web Form POST 數(shù)據(jù)呢?System.Net命名空間里面提供了兩個(gè)非常有用的類,一個(gè)是WebClient,另外一個(gè)是HttpWebRequest類。如果我們不需要通過代理服務(wù)器來上傳文件,那么非常簡(jiǎn)單,只需要簡(jiǎn)單的調(diào)用WebClient.UploadFile方法就能實(shí)現(xiàn)上傳文件:
private void button1_Click(object sender, System.EventArgs e)
{
WebClient myWebClient = new WebClient();
myWebClient.UploadFile("http://localhost/UploadFileWeb/WebForm1.aspx","POST",@"D:\Temp\Java\JavaStart\JavaStart2.exe");
}
是不是覺得很簡(jiǎn)單呢?確實(shí)就這么簡(jiǎn)單。
但是如果要通過代理服務(wù)器上傳又怎么辦呢?那就需要使用到HttpWebRequest,但是該類沒有Upload方法,但是幸運(yùn)的是我們通過Reflector反編譯了WebClient.UploadFile方法后,我們發(fā)現(xiàn)其內(nèi)部也是通過WebRequest來實(shí)現(xiàn)的,代碼如下:
public byte[] UploadFile(string address,string method, string fileName)
{
string text1;
string text2;
WebRequest request1;
string text3;
byte[] buffer1;
byte[] buffer2;
long num1;
byte[] buffer3;
int num2;
WebResponse response1;
byte[] buffer4;
DateTime time1;
long num3;
string[] textArray1;
FileStream stream1 = null;
try
{
fileName =Path.GetFullPath(fileName);
time1 =DateTime.Now;
num3 =time1.Ticks;
text1 ="---------------------" + num3.ToString("x");
if (this.m_headers== null)
{
this.m_headers = new WebHeaderCollection();
}
text2 =this.m_headers["Content-Type"];
if (text2 !=null)
{
if (text2.ToLower(CultureInfo.InvariantCulture).StartsWith("multipart/"))
{
throw new WebException(SR.GetString("net_webclient_Multipart"));
}
}
else
{
text2 = "application/octet-stream";
}
this.m_headers["Content-Type"] = "multipart/form-data;boundary=" + text1;
this.m_responseHeaders = null;
stream1 =new FileStream(fileName, FileMode.Open, FileAccess.Read);
request1 =WebRequest.Create(this.GetUri(address));
request1.Credentials = this.Credentials;
this.CopyHeadersTo(request1);
request1.Method = method;
textArray1 =new string[7];
textArray1[0] = "--";
textArray1[1] = text1;
textArray1[2] = "\r\nContent-Disposition: form-data;name=\"file\"; filename=\"";
textArray1[3] = Path.GetFileName(fileName);
textArray1[4] = "\"\r\nContent-Type: ";
textArray1[5]= text2;
textArray1[6] = "\r\n\r\n";
text3 =string.Concat(textArray1);
buffer1 =Encoding.UTF8.GetBytes(text3);
buffer2 =Encoding.ASCII.GetBytes("\r\n--" + text1 + "\r\n");
num1 =9223372036854775807;
try
{
num1 = stream1.Length;
request1.ContentLength = ((num1 + ((long) buffer1.Length)) + ((long)buffer2.Length));
}
catch
{
}
buffer3 =new byte[Math.Min(((int) 8192), ((int) num1))];
using(Stream stream2 = request1.GetRequestStream())
{
stream2.Write(buffer1, 0, buffer1.Length);
do
{
num2 = stream1.Read(buffer3, 0, buffer3.Length);
if (num2 != 0)
{
stream2.Write(buffer3, 0, num2);
}
}
while ((num2 != 0));
stream2.Write(buffer2, 0, buffer2.Length);
}
stream1.Close();
stream1 =null;
response1 =request1.GetResponse();
this.m_responseHeaders = response1.Headers;
returnthis.ResponseAsBytes(response1);
}
catch (Exception exception1)
{
if (stream1!= null)
{
stream1.Close();
stream1 = null;
}
if((exception1 is WebException) || (exception1 is SecurityException))
{
throw;
}
throw newWebException(SR.GetString("net_webclient"), exception1);
}
return buffer4;
}
在這段代碼里面其實(shí)最關(guān)鍵的就是如何模擬POST請(qǐng)求,通過分析代碼和監(jiān)視HTTP,我們可以發(fā)現(xiàn)模擬的POST格式如下:
-----------------------8c64f47716481f0 //時(shí)間戳
Content-Disposition:form-data; name="file"; filename="a.txt" //文件名
Content-Type: application/octet-stream