上一篇中提到Silverlight + WCF实现文件上传的一个缺点:一次性的将文件读到内存。显然,当文件的尺寸大到内存难以容纳时,这种方法是有问题的。
处理这个问题时,自然的会想到,可以边读边上传。实测的情况,该方法实现也很简单,下面简要描述一下。
1. 创建解决方案的方法和修改配置的方法同“Silverlight中用WCF实现文件快速上传(一)”,不再赘述。
2. Silverlight中的实现
辅助类:
public class UserFile
{
public string Name { get; set; } //文件名
public long Length { get; set; } //文件长度
public int BytesRead { get; set; } //本次读到的字节数
public long BytesSent { get; set; } //已经发送(上传)的字节数
public System.IO.FileStream FileStream { get; set; } //文件流
}
MainPage.cs中的实现:
public partial class MainPage : UserControl
{
private const int BUFFER_SIZE = 2097152; //2MB
private UserFile _file;
private byte[] _buffer;
private localService.Service1Client _client;
public MainPage()
{
btnUploadFile.Click += new RoutedEventHandler(Button_Click);
_buffer = new byte[BUFFER_SIZE];
_client = new localService.Service1Client();
//事件处理
_client.ActionUploadCompleted += newEventHandler<System.ComponentModel.AsyncCompletedEventArgs>(_client_ActionUploadCompleted);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//选择本地文件对话框
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "(*.*)|*.*";
//单选
openFileDialog.Multiselect = false;
if (openFileDialog.ShowDialog() == true)
{
_file = new UserFile();
FileInfo fileInfo = openFileDialog.File;
_file.Name = fileInfo.Name;
_file.Length = fileInfo.Length;
_file.BytesRead = 0;
_file.BytesSent = 0;
_file.FileStream = fileInfo.OpenRead();
//初始化进度条
prgUpload.Minimum = 0;
prgUpload.Maximum = Math.Ceiling((double)_file.Length / (double)_buffer.Length);
int bytesRead = _file.FileStream.Read(_buffer, 0, _buffer.Length);
if (bytesRead > 0)
{
_file.BytesRead = bytesRead;
_client.ActionUploadAsync(_file.Name, _buffer, false);
}
else
{
_file.FileStream.Close();
}
}
}
void _client_ActionUploadCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
if (e.Error == null)
{
_file.BytesSent += _file.BytesRead;
prgUpload.Value = Math.Ceiling((double)_file.BytesSent / (double)_buffer.Length); //更新进度条
if (_file.BytesSent < _file.Length)
{
int bytesRead = _file.FileStream.Read(_buffer, 0, _buffer.Length);
if (bytesRead > 0)
{
_file.BytesRead = bytesRead;
_client.ActionUploadAsync(_file.Name, _buffer, true);
}
else
{
_file.FileStream.Close();
}
}
else
{
_file.FileStream.Close();
}
}
}
}
3. 总结
本方法实现了边读文件边上传,实测时可以快速上传任意大小的文件。另外,还增加了上传的进度条。