在WCF下作大文件的上传,首先想到使用的就是Stream,这也是微软推荐的使用方式。处理流程是:首先把文件加载到内存中,加载完毕后传递数据。这种处理方式对小文件,值得推荐,比如几K,几十k的图片文件,文本文件对大文件就不适用,比如10G的电影,把10G的数据加载到缓存中再传递,这是不可想象的。这个时候我们想到的就是断点续传。由于数据量很大。会导致当前程序阻塞,所以采用异步发送的方式,以进度条显示出来,这也是本篇文章所要实现的功能.
另外,目前BasicHttpBinding, NetTcpBinding, 和NetNamedPipeBinding 支持流处理模型,其他的不支持,这也影响stream的使用。解释几个重要的概念以及实现的方式:1、断点续传:就是在上一次下载/上传断开的位置开始继续下载/上传。微软已经提供好了这样的方法: BinaryWriter 这个是二进制的写入器,看下面:
namespace System.IO
{
public class BinaryWriter : IDisposable
{
public virtual long Seek(int offset, SeekOrigin origin); //设置当前流中的位置,第一个参数表示偏移量,第二个参数表示偏移量的参考依据
public virtual void Write(byte[] buffer); //把数据写入Seek方法设置的位置
}
}
2、异步线程:就是使用后台程序,不用阻塞当前线程,使用backgroundWorker组建,可以大大减少代码的编写量 下面的操作都是与WCF相关的部分。首先我们要定义一个数据契约用来传递数据:
[DataContract]
public class FileInfo
{
//文件名
[DataMember]
public string Name { get; set; }
//文件字节大小
[DataMember]
public long Length { get; set; }
//文件的偏移量
[DataMember]
public long Offset { get; set; }
//传递的字节数
[DataMember]
public byte[] Data { get; set; }
//创建时间
[DataMember]
public DateTime CreateTime { get; set; }
}
接着定义操作的契约:
[ServiceContract]
public interface IFilesLoad
{
[OperationContract]
List<FileInfo> GetFilesList(); //获得以已经上传的文件列表
[OperationContract]
FileInfo GetFiles(string fileName); //根据文件名寻找文件是否存在,返回文件的字节长度
[OperationContract]
FileInfo UplodaFile(FileInfo file); //上传文件
}
定义了契约,下面就要来实现契约,这里仅仅粘贴重要部分,在后面可以下载源代码
public Fish.DataContracts.FileInfo UplodaFile(Fish.DataContracts.FileInfo file)
{
string filePath = System.Configuration.ConfigurationManager.AppSettings["filePath"] + "/" + file.Name;//获取文件的路径,已经保存的文件名
FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate);//打开文件
long offset = file.Offset; //file.Offset 文件偏移位置,表示从这个位置开始进行后面的数据添加
BinaryWriter writer = new BinaryWriter(fs);//初始化文件写入器
writer.Seek((int)offset, SeekOrigin.Begin);//设置文件的写入位置
writer.Write(file.Data);//写入数据
file.Offset = fs.Length;//返回追加数据后的文件位置
file.Data = null;
writer.Close();
fs.Close();
return file;
}
下面来进行服务端得WCF配置
<system.serviceModel>
<services>
<!-- 文件断点续传 -->
<service behaviorConfiguration="DefaultBehavior" name="Fish.ServiceImpl.FilesService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration ="StreamedHTTP" contract="Fish.ServiceInterfaces.IFilesLoad"></endpoint>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/Fish/FilesService"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="DefaultBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="StreamedHTTP" maxReceivedMessageSize="2000000000000" messageEncoding="Mtom" transferMode="Streamed">
<readerQuotas maxArrayLength="20000000"/>
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
这里最要的是设置maxReceivedMessageSize, messageEncoding。比较重要的是设置为Mtom,可以提高30%的效率,这是wcf特意为大文件提供的。下面看客户端代码:
var fileManger = Common.ServiceBroker.FindService<IFilesLoad>(); //创建WCF代理
string localPath = e.Argument as string;
string fileName = localPath.Substring(localPath.LastIndexOf('\\') + 1);//获得文件本地文件地址
int maxSiz = 1024 * 100; //设置每次传100k
FileStream stream = System.IO.File.OpenRead(localPath); //读取本地文件
Fish.DataContracts.FileInfo file = fileManger.GetFiles(fileName); //更加文件名,查询服务中是否存在该文件
if (file == null) //表示文件不存在
{
file = new Fish.DataContracts.FileInfo();
file.Offset = 0; //设置文件从开始位置进行数据传递
}
file.Name = fileName;
file.Length = stream.Length;
if (file.Length == file.Offset) //如果文件的长度等于文件的偏移量,说明文件已经上传完成
{
MessageBox.Show("该文件已经在服务器中,不用上传!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
else
{
while (file.Length != file.Offset) //循环的读取文件,上传,直到文件的长度等于文件的偏移量
{
file.Data = new byte[file.Length - file.Offset <= maxSiz ? file.Length - file.Offset : maxSiz]; //设置传递的数据的大小
stream.Position = file.Offset; //设置本地文件数据的读取位置
stream.Read(file.Data, 0, file.Data.Length);//把数据写入到file.Data中
file = fileManger.UplodaFile(file); //上传
e.Result = file.Offset;
(sender as BackgroundWorker).ReportProgress((int)(((double)file.Offset / (double)((long)file.Length)) * 100), file.Offset);
if (this.backgroundWorker1.CancellationPending)
return;
}
}
stream.Close();
Common.ServiceBroker.DisposeService<IFilesLoad>(fileManger); //关闭wcf
最后是最后运行的效果: 代码地址:http://files.cnblogs.com/wanqiming/Upload.rar
分享到:
相关推荐
断点续传程序事例,可以直接应用到工程中。
WCF大文件断点下载 一个服务端,使用WCF自承载,默认采用了RESF模式,直接提供了HTTP下载,也可以开启NET TCP等其它模式。HTTP下载时,IE是不支持断点续传的,下载软件中,只有网络传送带支持断点续传,其它的软件...
采用wcf和serverlight技术实现断点续传!
wcf异步方式分为:客户端异步和服务端异步,本代码为服务端异步。 注:在win10下调试会报错,需要管理员权限,可以生成后右键-管理员权限运行。
Apress Pro WCF 4 Practical Microsoft SOA Implementation, 2nd Part I: Introducing Windows Communication Foundation ■Chapter 1: WCF and SOA Basics ■Chapter 2: What’s New in WCF 4 ■Chapter 3: ...
WCF实现简单的文件上传与下载,几十兆的文档上传和下载都测试过,没问题。
该软件利用.Net平台下的WCF远程通信服务框架,实现的具备断点续传功能的文件上传模块
摘自网友博客 非常不错的学习WCF的文章
该示例,整合了C#文件传输中的SOCKET同步、异步、WCF同步、异步,并分别提供了进度条,以便查看各类传输的效率(SOCKET同步>SOCKET异步>WCF同步>WCF异步)。 运行的时候,需要自己添加一个可供传输的文件。可查看...
介绍Silverlight与wcf异步调用,修改xap文件内的配置。内附源代码实例。
这是本人研究WCF双工通讯...服务器可以群发消息或传文件,也可以对单一客户端发消息传文件。客户端只能向服务端发消息或者传文件。 目前的不足点:1.客户端之间不能发消息。2.当客户端异常情况退出时,服务端无法知道。
WCF 上传大文件的问题.。测试项目
wcf上传文件的范例,可以上传大文件,还提供断点续传的功能。
wcf多线程和异步操作 异步服务的调用 异步服务的实现 读取文件demo
讲解WCF技术的,适合各种阶段的学习。从入门到进阶。
自己编写的示例程序,对初学着很有借鉴意义。 WCF文件传输示例,大文件采用stream传输,有效减少内存占用。
实现WCF 文件上传下载 ,断点续传,检测文件
WCF异步调用的小例子,非常好的一个例子~~
我的WCF之旅- 创建一个简单的WCF程序 - Artech WCF入门之选绝佳的例子 代源源于:《WCF全面解析 上》 编程工具:VS2010 语言:C# blog 《IIS站点中部署 WCF项目》
通过WCF进行远程文件操作,包括上传下载,复制,删除,创建文件夹,删除文件夹,以及上传下载进度显示