时间:2021-07-01 10:21:17 帮助过:28人阅读
- <br><br>/* <br><br>本文件位于 Web 共享目录的 bin 子目录下,通过执行如下命令行编译: <br>csc /t:library updownload.asmx.cs <br><br>*/ <br>using System.Diagnostics; <br>using System.Web; <br>using System.Web.Services; <br>using System.IO; <br>using System; <br><br>public class Service1 : System.Web.Services.WebService <br>{ <br> [WebMethod] <br> public string HelloWorld() <br> { <br> return "Hello World"; <br> } <br><br> //从 Web Method 本身,其实看不出 "同步" 还是 "异步" <br> [WebMethod(Description = "为了支持多点分块异步上传文件,此方法必须由客户端预先调用,以便在服务器端生成指定 FileName 和 Length 大小的空白文件预定空间! 建议客户端同步调用")] <br> public string CreateBlankFile(string FileName,int Length) //建议由客户端同步调用 <br> { <br> FileStream fs = new FileStream(Server.MapPath(".") + "\\" + FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); <br> fs.Write(new byte[Length], 0, Length); <br> fs.Close(); <br> fs = null; <br> return FileName + " (" + Length + ") 空白文件已经创建!"; <br> } <br><br> [WebMethod(Description = "提供一个用于一次完整上传整个文件的方法! 建议客户端同步调用")] <br> public string UploadFileBytes(byte[] Bytes,string FileName) <br> { <br> return UploadFileChunkBytes(Bytes, 0, FileName); <br> } <br><br> [WebMethod(Description = "提供一个用于一次只上传由 Position 位置起始的, Bytes 字节的 FileName 文件块存入服务器端相应文件的相应字节位置! 建议客户端异步调用")] <br> // 这里只要多提供一个 Position 参数,余下的再由客户端调用异步的该方法,就轻松达到目的了! <br> public string UploadFileChunkBytes(byte[] Bytes,int Position,string FileName) <br> { <br> try <br> { <br> FileStream fs = new FileStream(Server.MapPath(".") + "\\" + FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite); <br> //该 Bytes 的字节要写到 服务器端 相应文件的从 Position 开始的字节 <br> fs.Position = Position; <br> fs.Write(Bytes, 0, Bytes.Length); <br> fs.Close(); <br> fs = null; <br> return FileName + " 文件块: 位置[" + Position + "," + (Position + Bytes.Length) + "] 大小(" + Bytes.Length + ") 上传成功!"; <br> } <br> catch (Exception e) <br> { <br> return e.Message; <br> } <br> } <br><br> [WebMethod] <br> public byte[] DownloadFileBytes(string FileName) <br> { <br> if (File.Exists(FileName)) <br> { <br> try <br> { <br> FileStream fs = File.OpenRead(FileName); <br> int i = (int) fs.Length; <br> byte[] ba = new byte[i]; <br> fs.Read(ba,0,i); <br> fs.Close(); <br> return ba; <br> } <br> catch <br> { <br> return new byte[0]; <br> } <br> } <br> else <br> { <br> return new byte[0]; <br> } <br> } <br>} <br><br><br>//======================================================================= <br><br>Client Side: <br>3. UpDownloadProxy.cs : <br> 本文件由如下命令生成 <br> % Visual Studio .Net 2003 安装目录下的 %\SDK\v1.1\Bin\wsdl.exe <br> 具体命令行如下: <br> wsdl.exe /l:CS /out:UpDownloadProxy.cs http://localhost/MyWebServices/updownload.asmx?wsdl <br> 生成的本地的客户端代理类代码里已经为每个 Web Method 生成了可异步和同步执行的方法,例如: <br> public string HelloWorld() {} <br> public System.IAsyncResult BeginHelloWorld(...) {} <br> public string EndHelloWorld(...) {} <br><br> 下面是该命令行生成的完整的 UpDownloadProxy.cs 代码,就不修改了: <br>/* <br><br>通过执行如下命令行编译,生成 UpDownloadProxy.dll : <br>csc /t:library UpDownloadProxy.cs <br><br>*/ <br><br>//------------------------------------------------------------------------------ <br>// <autogenerated> <br>// This code was generated by a tool. <br>// Runtime Version: 1.1.4322.573 <br>// <br>// Changes to this file may cause incorrect behavior and will be lost if <br>// the code is regenerated. <br>// </autogenerated> <br>//------------------------------------------------------------------------------ <br><br>// <br>// 此源代码由 wsdl, Version=1.1.4322.573 自动生成。 <br>// <br>using System.Diagnostics; <br>using System.Xml.Serialization; <br>using System; <br>using System.Web.Services.Protocols; <br>using System.ComponentModel; <br>using System.Web.Services; <br><br><br>/// <remarks/> <br>[System.Diagnostics.DebuggerStepThroughAttribute()] <br>[System.ComponentModel.DesignerCategoryAttribute("code")] <br>[System.Web.Services.WebServiceBindingAttribute(Name="Service1Soap", Namespace="http://tempuri.org/")] <br>public class Service1 : System.Web.Services.Protocols.SoapHttpClientProtocol { <br><br> /// <remarks/> <br> public Service1() { <br> this.Url = "http://localhost/MyWebServices/updownload.asmx"; <br> } <br><br> /// <remarks/> <br> [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/HelloWorld", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] <br> public string HelloWorld() { <br> object[] results = this.Invoke("HelloWorld", new object[0]); <br> return ((string)(results[0])); <br> } <br><br> /// <remarks/> <br> public System.IAsyncResult BeginHelloWorld(System.AsyncCallback callback, object asyncState) { <br> return this.BeginInvoke("HelloWorld", new object[0], callback, asyncState); <br> } <br><br> /// <remarks/> <br> public string EndHelloWorld(System.IAsyncResult asyncResult) { <br> object[] results = this.EndInvoke(asyncResult); <br> return ((string)(results[0])); <br> } <br><br> /// <remarks/> <br> [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/CreateBlankFile", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] <br> public string CreateBlankFile(string FileName, int Length) { <br> object[] results = this.Invoke("CreateBlankFile", new object[] { <br> FileName, <br> Length}); <br> return ((string)(results[0])); <br> } <br><br> /// <remarks/> <br> public System.IAsyncResult BeginCreateBlankFile(string FileName, int Length, System.AsyncCallback callback, object asyncState) { <br> return this.BeginInvoke("CreateBlankFile", new object[] { <br> FileName, <br> Length}, callback, asyncState); <br> } <br><br> /// <remarks/> <br> public string EndCreateBlankFile(System.IAsyncResult asyncResult) { <br> object[] results = this.EndInvoke(asyncResult); <br> return ((string)(results[0])); <br> } <br><br> /// <remarks/> <br> [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/UploadFileBytes", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] <br> public string UploadFileBytes([System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] System.Byte[] Bytes, string FileName) { <br> object[] results = this.Invoke("UploadFileBytes", new object[] { <br> Bytes, <br> FileName}); <br> return ((string)(results[0])); <br> } <br><br> /// <remarks/> <br> public System.IAsyncResult BeginUploadFileBytes(System.Byte[] Bytes, string FileName, System.AsyncCallback callback, object asyncState) { <br> return this.BeginInvoke("UploadFileBytes", new object[] { <br> Bytes, <br> FileName}, callback, asyncState); <br> } <br><br> /// <remarks/> <br> public string EndUploadFileBytes(System.IAsyncResult asyncResult) { <br> object[] results = this.EndInvoke(asyncResult); <br> return ((string)(results[0])); <br> } <br><br> /// <remarks/> <br> [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/UploadFileChunkBytes", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] <br> public string UploadFileChunkBytes([System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] System.Byte[] Bytes, int Position, string FileName) { <br> object[] results = this.Invoke("UploadFileChunkBytes", new object[] { <br> Bytes, <br> Position, <br> FileName}); <br> return ((string)(results[0])); <br> } <br><br> /// <remarks/> <br> public System.IAsyncResult BeginUploadFileChunkBytes(System.Byte[] Bytes, int Position, string FileName, System.AsyncCallback callback, object asyncState) { <br> return this.BeginInvoke("UploadFileChunkBytes", new object[] { <br> Bytes, <br> Position, <br> FileName}, callback, asyncState); <br> } <br><br> /// <remarks/> <br> public string EndUploadFileChunkBytes(System.IAsyncResult asyncResult) { <br> object[] results = this.EndInvoke(asyncResult); <br> return ((string)(results[0])); <br> } <br><br> /// <remarks/> <br> [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/DownloadFileBytes", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] <br> [return: System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] <br> public System.Byte[] DownloadFileBytes(string FileName) { <br> object[] results = this.Invoke("DownloadFileBytes", new object[] { <br> FileName}); <br> return ((System.Byte[])(results[0])); <br> } <br><br> /// <remarks/> <br> public System.IAsyncResult BeginDownloadFileBytes(string FileName, System.AsyncCallback callback, object asyncState) { <br> return this.BeginInvoke("DownloadFileBytes", new object[] { <br> FileName}, callback, asyncState); <br> } <br><br> /// <remarks/> <br> public System.Byte[] EndDownloadFileBytes(System.IAsyncResult asyncResult) { <br> object[] results = this.EndInvoke(asyncResult); <br> return ((System.Byte[])(results[0])); <br> } <br>} <br><br>//======================================================================= <br>4. UpDownloadClient.cs : <br> 该程序才是真正实现文件分块多点异步上传的核心代码: <br><br>/* <br><br>通过执行如下命令行编译: <br>csc updownloadClient.cs /r:updownloadproxy.dll <br><br>*/ <br>using System; <br>using System.IO; <br><br>public class Class1 <br>{ <br> static void Main(string[] args) <br> { <br> //Download(ServerSidepath, ClientSidePath) <br> Download(@"e:\test.jpg", @"f:\test_local.jpg"); <br> System.Console.WriteLine("down End"); <br><br> System.Console.WriteLine("同步 up file exec ..."); <br> UploadFile(@"e:\Northwind.mdb"); <br> System.Console.WriteLine("同步 up file End\n"); <br><br> System.Console.WriteLine("异步 up chunks exec ..."); <br> UploadFileChunks(@"e:\test.rar", 64); <br> System.Console.ReadLine(); <br> } <br><br> public static void UploadFile(string LocalFileName) <br> { <br> Service1 xx = new Service1(); <br> FileStream fs = new FileStream(LocalFileName, FileMode.Open); //Client Side Path <br> byte[] buffer = new byte[fs.Length]; <br> fs.Read(buffer, 0, buffer.Length); <br> //调用 "同步执行" 的本地 Web Sevices 代理类的 方法,相当于同步调用了 Web Method ! <br> xx.UploadFileBytes(buffer, System.IO.Path.GetFileName(LocalFileName)); <br> } <br><br> //指定要上传的本地文件的路径,及每次上传文件块的大小 <br> public static void UploadFileChunks(string LocalFileName,int ChunkSize) <br> { <br> Service1 xx = new Service1(); <br> string filename = System.IO.Path.GetFileName(LocalFileName); <br><br> FileStream fs = new FileStream(LocalFileName, FileMode.Open); //Client Side Path <br> //fs = File.OpenRead(LocalFileName); <br><br> int r = (int) fs.Length; //用于记录剩余还未上传的字节数,初值是文件的大小 <br><br> //调用 "同步执行" 的本地 Web Sevices 代理类的 方法,相当于同步调用了 Web Method ! <br> //预定服务器端空间 <br> xx.CreateBlankFile(filename,r); <br> int size = ChunkSize * 1024; <br> int k = 0; //用于记录已经上传的字节数 <br> i++; //用于记录上传的文件块数 <br> while (r >= size) <br> { <br> byte[] buffer = new byte[size]; <br> fs.Read(buffer,0,buffer.Length); <br> //调用 "异步执行" 的本地 Web Sevices 代理类的 方法,相当于异步调用了 Web Method ! <br> //该 buffer 的字节要写到 服务器端 相应文件的从 Position = k 开始的字节 <br> xx.BeginUploadFileChunkBytes(buffer,k,filename,new AsyncCallback(UploadFileChunkCallback),xx); <br> k += size; <br> r -= size; <br> i++; <br> } <br> if (r > 0) //剩余的零头 <br> { <br> byte[] buffer = new byte[r]; <br> fs.Read(buffer,0,buffer.Length); <br> //调用 "异步执行" 的本地 Web Sevices 代理类的 方法,相当于异步调用了 Web Method ! <br> //该 buffer 的字节要写到 服务器端 相应文件的从 Position = k 开始的字节 <br> xx.BeginUploadFileChunkBytes(buffer,k,filename,new AsyncCallback(UploadFileChunkCallback),xx); <br> i++; <br> } <br> fs.Close(); <br><br> } <br><br> private static int i = -1; //用于记录上传的文件块数 <br><br> private static void UploadFileChunkCallback(IAsyncResult ar) <br> { <br> Service1 x = (Service1) ar.AsyncState; <br> Console.WriteLine(x.EndUploadFileChunkBytes(ar)); <br> if ( --i == 0) <br> { <br> Console.WriteLine("异步 up all chunks end"); <br> } <br> } <br><br> public static void Download(string ServerSideFileName,string LocalFileName) <br> { <br> Service1 xx = new Service1(); <br> byte[] ba = xx.DownloadFileBytes(ServerSideFileName); //Server Side Path <br><br> FileStream fs = new FileStream(LocalFileName, FileMode.Create); //Client Side Path <br> fs.Write(ba,0,ba.Length); <br> fs.Close(); <br> } <br>} <br><br><br>//=========================================================================== <br>至此我们通过纯手工的方式完成了任务,之所以不用 VS 就是为了让码子简洁明了! <br>Microshaoft .Night 就是这么平易近人! (PMPMP to MS) <br>通过 Web Sevices 上传文件非常简单,甚至比传统的 http Web 上传还简单! <br>同时较轻松地就实现了文件分块多点异步上传: <br>Server 端代码没啥特殊的! <br>Client 端代码稍微复杂些! <br>