C#实现大文件拷贝
warensoft 中科院计算所培训中心
以前的Blog中提到过如何利用FileStream实现文件拷贝,作法是利用FileStream将文件整个加载到内存中的Byte[]中,然后再这个数组直接利用FileStream写入到另外一个位置上,这么做有以下几个问题:
Ø 文件不能太大,文件太大,会占用过多内存,会导致系统内存不足
Ø 整个文件拷贝会无法精确查看拷贝进度
下面我们利用FileStream实现大文件的分块拷贝功能,并且显示出拷贝进度
大家如何有什么问题请给我发邮件:warensoft@163.com
本文的代码下载地址:https://files.cnblogs.com/warensoft/FileCopy.rar
1. 建立一个Window应用程序,如下图所示:
2. 在界面上添加控件,如下图所示:
上面两个按钮,分别用来设置要打开的原文件,以及要保存到的位置,它们的Click事件的代码对应如下:
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
///
/// 用于打开源文件
///
///
///
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog of = new OpenFileDialog();
of.ShowDialog();
this.textBox1.Text = of.FileName;
}
///
/// 用于设置保存文件的位置
///
///
///
private void button2_Click(object sender, EventArgs e)
{
SaveFileDialog sf = new SaveFileDialog();
sf.ShowDialog();
this.textBox2.Text = sf.FileName;
}
/// 用于打开源文件
///
///
///
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog of = new OpenFileDialog();
of.ShowDialog();
this.textBox1.Text = of.FileName;
}
///
/// 用于设置保存文件的位置
///
///
///
private void button2_Click(object sender, EventArgs e)
{
SaveFileDialog sf = new SaveFileDialog();
sf.ShowDialog();
this.textBox2.Text = sf.FileName;
}
3.
添加Copy按钮的Click事件,该代码为大文件拷贝的核心代码,其主要过程就是利用FileStream读一点到内存,再利用FileStream写一点到文件,只要没有读完,那么前面这个过程就不断的重复,其代码如下所示:
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
private void button3_Click(object sender, EventArgs e)
{
Thread thread = null;
//为了不让界面死掉,要将该操作放在一个线程中
thread = new Thread
(
() =>
{
//告诉系统不去检测非法的跨线程调用
CheckForIllegalCrossThreadCalls = false;
//创建一个文件流指向源文件
FileStream fsRead = new FileStream(this.textBox1.Text, FileMode.Open);
//创建一个文件流指向目标文件
FileStream fsWrite = new FileStream(this.textBox2.Text, FileMode.Create);
//记录一下该文件的长度
long fileLength = fsRead.Length;
//定义一个1M的缓冲区
byte[] buffer = new byte[1024 * 1024];
//先读取一次,并且将读取到的真正内容长度记录下来
int readLength = fsRead.Read(buffer, 0, buffer.Length);
//用来记录已经将多少内容写入到了文件中
long readCount = 0;
//只要读取到的内容不为0就接着读
while (readLength!=0)
{
//将前面已经读取到内存中的数据写入到文件中
fsWrite.Write(buffer ,0,readLength);
//已经读取的数量累加
readCount += readLength;
//计算已经读取的数据百分比
int percentage =(int)( readCount * 100 / fileLength);
this.progressBar1.Value = percentage;
//进行下一次读取
readLength = fsRead.Read(buffer, 0, buffer.Length);
}
fsRead.Close();
fsWrite.Close();
//清空缓冲区
buffer = null;
//回收一下内存
GC.Collect();
thread.Abort();
}
);
thread.Start();
}
{
Thread thread = null;
//为了不让界面死掉,要将该操作放在一个线程中
thread = new Thread
(
() =>
{
//告诉系统不去检测非法的跨线程调用
CheckForIllegalCrossThreadCalls = false;
//创建一个文件流指向源文件
FileStream fsRead = new FileStream(this.textBox1.Text, FileMode.Open);
//创建一个文件流指向目标文件
FileStream fsWrite = new FileStream(this.textBox2.Text, FileMode.Create);
//记录一下该文件的长度
long fileLength = fsRead.Length;
//定义一个1M的缓冲区
byte[] buffer = new byte[1024 * 1024];
//先读取一次,并且将读取到的真正内容长度记录下来
int readLength = fsRead.Read(buffer, 0, buffer.Length);
//用来记录已经将多少内容写入到了文件中
long readCount = 0;
//只要读取到的内容不为0就接着读
while (readLength!=0)
{
//将前面已经读取到内存中的数据写入到文件中
fsWrite.Write(buffer ,0,readLength);
//已经读取的数量累加
readCount += readLength;
//计算已经读取的数据百分比
int percentage =(int)( readCount * 100 / fileLength);
this.progressBar1.Value = percentage;
//进行下一次读取
readLength = fsRead.Read(buffer, 0, buffer.Length);
}
fsRead.Close();
fsWrite.Close();
//清空缓冲区
buffer = null;
//回收一下内存
GC.Collect();
thread.Abort();
}
);
thread.Start();
}