寻找最快的大文件拷贝方法(转自:http://www.cnblogs.com/hesicong/archive/2007/08/18/860763.html)
来源:互联网 发布:新闻门户后台 php 编辑:程序博客网 时间:2024/05/18 02:28
众所周知微软的操作系统自带的拷贝是很“弱智”的,速度不高,无断点续传,而且拷贝会拖累其他的应用程序,占用大量的文件缓存。所以很多高级的拷贝工具孕育而生,用过最好的是FastCopy。FastCopy的拷贝速度基本上可以达到磁盘的极限,还因为他开源,所以可以看到其实现。但是很可惜他的工程是VC6的,而且源代码注释都是日文的,不仅如此,其源代码风格很让人迷惑。证实了我的那句话:开源软件的最高境界就是,我开源了,你看不懂;等你看懂了,已经过时了。
要达到最快的拷贝速度和减少对内存的占用,需要对拷贝的过程有一个了解。拷贝无非就是将文件的数据读出来,然后再写进去的一个过程。XP操作系统自带的拷贝工具会首先打开文件句柄,然后将一块数据读取到缓存中,然后再写入到磁盘中。打开“Windows任务管理器”,进程,查看,选择列,打开I/O读取字节,I/O写入字节。拷贝一个文件,注意explorer.exe进程即可看到整个读写过程。基本上可以看到XP对于文件拷贝几乎是属于同时进行的,换句话说其开的缓存比较小,但其效率可能并不见得很高。在我的200G Seagate 7200.8硬盘上,复制速度在15M/s左右。而这个硬盘的平均读取速度在40M/s,平均写入速度也在35M/s以上。
在Vista下面文件拷贝做了一些优化,虽然一些BUG导致复制小文件会感觉很慢,但是复制大文件的思路已经不同于XP了。还是打开任务管理器,进行同样的操作。会发现Vista的会读取将近100M后,再将文件写入磁盘。explorer.exe进程也会在拷贝的瞬间内存占用飙升到100M以上,我的电脑商测试是120M左右,而复制完成以后内存占用将恢复正常。Vista的状态显示复制速度在18M/s左右。还是没有达到硬盘的极限速度。
观察Vista和XP的拷贝过程可以得出一个结论,Vista试图对磁盘的拷贝做优化了,但是其无论XP的分小块的复制,还是Vista的大缓存大块复制,都不能达到磁盘的最快速度。
在两个操作系统复制的过程中,你会发现一个有趣的现象。XP的“任务管理器”的“性能”页面种的“物理内存”种的“系统缓存”的值会不断的增大,大到一个值以后就不会在增长。系统缓存主要用于缓存使用过的一些程序的内存、缓存打开并读写过的文件,已达到更快的读写速度。Win32 API的CreateFile函数默认是使用系统缓存的读写,所以简单的用CreateFile打开的文件是要先到系统缓存的。explorer也是这样,所以当你打开了比较多的后台程序,复制完一个大文件以后,再打开这些后台程序就变得十分缓慢,硬盘不停的读取。这是因为文件缓存占用了太多的内存空间的缘故,将一些程序缓存占用了,所以后台程序会变得十分缓慢。Vista下面这种情况要好一些。虽然这样的设计可以加速很多文件操作的应用,但是对于文件拷贝这样的一次性操作,使用系统缓存固然就是浪费资源了。
我还发现当使用FastCopy的拷贝大文件的时候会出现另一个现象,就是“系统缓存”会骤降,磁盘读写速度基本达到极限。在XP下面能够改善后台程序的性能,因为此时FastCopy使用的是不使用操作系统缓存的读写操作,软件自生打开了一个32M的缓存(可自定义)。Vista下面的行为有些古怪,“系统缓存”也会减少,但是当复制完以后,硬盘会不断的读取,直到达到复制之前的大小,XP无此现象。
拷贝速度(MB/s)1M11.99n/a2M15.19n/a4M20.42n/a8M23.87n/a16M25.09n/a32M25.9311.3164Mn/a15.89128Mn/a17.02由于将在程序中将bufferSize设置为64M会导致出现异常,所以64M没有数据。对于使用缓存的拷贝的速度小于32M缓存的读取速度很慢,没有进行更多的测试。
结果很明显,在同样的自定义缓存大小的同时,不使用系统缓存的拷贝速度明显要高于使用系统缓存的拷贝速度。当不使用系统缓存的拷贝时,当缓存大小等于磁盘物理缓存大小的时候拷贝速度就达到了90%的最大速度;当等于磁盘物理缓存2倍时基本达到磁盘存取极限。由于上述原因,这也就是为什么FastCopy不使用系统缓存的缘故了。
当然如果大家有什么更好的看法或想法,欢迎留言探讨,谢谢!
要达到最快的拷贝速度和减少对内存的占用,需要对拷贝的过程有一个了解。拷贝无非就是将文件的数据读出来,然后再写进去的一个过程。XP操作系统自带的拷贝工具会首先打开文件句柄,然后将一块数据读取到缓存中,然后再写入到磁盘中。打开“Windows任务管理器”,进程,查看,选择列,打开I/O读取字节,I/O写入字节。拷贝一个文件,注意explorer.exe进程即可看到整个读写过程。基本上可以看到XP对于文件拷贝几乎是属于同时进行的,换句话说其开的缓存比较小,但其效率可能并不见得很高。在我的200G Seagate 7200.8硬盘上,复制速度在15M/s左右。而这个硬盘的平均读取速度在40M/s,平均写入速度也在35M/s以上。
在Vista下面文件拷贝做了一些优化,虽然一些BUG导致复制小文件会感觉很慢,但是复制大文件的思路已经不同于XP了。还是打开任务管理器,进行同样的操作。会发现Vista的会读取将近100M后,再将文件写入磁盘。explorer.exe进程也会在拷贝的瞬间内存占用飙升到100M以上,我的电脑商测试是120M左右,而复制完成以后内存占用将恢复正常。Vista的状态显示复制速度在18M/s左右。还是没有达到硬盘的极限速度。
观察Vista和XP的拷贝过程可以得出一个结论,Vista试图对磁盘的拷贝做优化了,但是其无论XP的分小块的复制,还是Vista的大缓存大块复制,都不能达到磁盘的最快速度。
在两个操作系统复制的过程中,你会发现一个有趣的现象。XP的“任务管理器”的“性能”页面种的“物理内存”种的“系统缓存”的值会不断的增大,大到一个值以后就不会在增长。系统缓存主要用于缓存使用过的一些程序的内存、缓存打开并读写过的文件,已达到更快的读写速度。Win32 API的CreateFile函数默认是使用系统缓存的读写,所以简单的用CreateFile打开的文件是要先到系统缓存的。explorer也是这样,所以当你打开了比较多的后台程序,复制完一个大文件以后,再打开这些后台程序就变得十分缓慢,硬盘不停的读取。这是因为文件缓存占用了太多的内存空间的缘故,将一些程序缓存占用了,所以后台程序会变得十分缓慢。Vista下面这种情况要好一些。虽然这样的设计可以加速很多文件操作的应用,但是对于文件拷贝这样的一次性操作,使用系统缓存固然就是浪费资源了。
我还发现当使用FastCopy的拷贝大文件的时候会出现另一个现象,就是“系统缓存”会骤降,磁盘读写速度基本达到极限。在XP下面能够改善后台程序的性能,因为此时FastCopy使用的是不使用操作系统缓存的读写操作,软件自生打开了一个32M的缓存(可自定义)。Vista下面的行为有些古怪,“系统缓存”也会减少,但是当复制完以后,硬盘会不断的读取,直到达到复制之前的大小,XP无此现象。
那么怎么样才能达到极限速度呢?是需要缓存还是不需要缓存呢?要缓存需要多大的缓存才好呢?为此我做了一个小实验。
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.IO;using Microsoft.Win32.SafeHandles;using System.Runtime.InteropServices;namespace csharp{ class Program { public const short FILE_ATTRIBUTE_NORMAL = 0x80; public const short INVALID_HANDLE_VALUE = -1; public const uint GENERIC_READ = 0x80000000; public const uint GENERIC_WRITE = 0x40000000; public const uint CREATE_NEW = 1; public const uint CREATE_ALWAYS = 2; public const uint OPEN_EXISTING = 3; public const uint FILE_FLAG_NO_BUFFERING = 0x20000000; public const uint FILE_FLAG_WRITE_THROUGH = 0x80000000; public const uint FILE_SHARE_READ = 0x00000001; public const uint FILE_SHARE_WRITE = 0x00000002; // Use interop to call the CreateFile function. // For more information about CreateFile, // see the unmanaged MSDN reference library. [DllImport("kernel32.dll", SetLastError = true)] static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile); static void Main(string[] args) { bool useBuffer = false; SafeFileHandle fr = CreateFile("d:\\source", GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero, OPEN_EXISTING, useBuffer? 0:FILE_FLAG_NO_BUFFERING , IntPtr.Zero); SafeFileHandle fw = CreateFile("d:\\dest", GENERIC_WRITE, FILE_SHARE_READ, IntPtr.Zero, CREATE_ALWAYS,useBuffer? 0:(FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH), IntPtr.Zero); int bufferSize = useBuffer? 1024*1024*32:1024 * 1024 * 32; FileStream fsr = new FileStream(fr, FileAccess.Read); FileStream fsw = new FileStream(fw, FileAccess.Write); BinaryReader br = new BinaryReader(fsr); BinaryWriter bw = new BinaryWriter(fsw); byte[] buffer = new byte[bufferSize]; Int64 len = fsr.Length; DateTime start = DateTime.Now; TimeSpan ts; while (fsr.Position < fsr.Length) { int readCount = br.Read(buffer, 0, bufferSize); bw.Write(buffer, 0, readCount); ts = DateTime.Now.Subtract(start); double speed=(double)fsr.Position / ts.TotalMilliseconds * 1000 / (1024 * 1024); double progress=(double)fsr.Position / len * 100; Console.WriteLine("Speed:{0}, Progress:{1}",speed ,progress ); } br.Close(); bw.Close(); sw.Close(); Console.WriteLine("End"); Console.ReadLine(); } }}
整个程序的思路比较简单,打开文件,读取数据到自定义的缓存,然后写入数据,关闭文件。.NET默认的FileStream默认是缓存的读写,而且没有参数指定非缓存的读写。但好在FileStream的一个构造函数能够很方便的传递一个句柄并为之所用。查阅MSDN的SafeFileHandle时发现了CreateFile的用法,只需要传递一个FILE_FLAG_NO_BUFFERING给CreateFile,就可以实现不使用系统缓存的读写。但使用非缓存的读写有一些操作上的限制,详细的可以见MSDN的相关文档。
运行以上程序,对一个Segate 80G的硬盘的D盘(硬盘自身缓存8M,其拷贝极限速度在26M/s左右)的一个大文件进行复制操作,得到的结果如下:
不使用系统缓存
拷贝速度(MB/s)
拷贝速度(MB/s)1M11.99n/a2M15.19n/a4M20.42n/a8M23.87n/a16M25.09n/a32M25.9311.3164Mn/a15.89128Mn/a17.02由于将在程序中将bufferSize设置为64M会导致出现异常,所以64M没有数据。对于使用缓存的拷贝的速度小于32M缓存的读取速度很慢,没有进行更多的测试。
结果很明显,在同样的自定义缓存大小的同时,不使用系统缓存的拷贝速度明显要高于使用系统缓存的拷贝速度。当不使用系统缓存的拷贝时,当缓存大小等于磁盘物理缓存大小的时候拷贝速度就达到了90%的最大速度;当等于磁盘物理缓存2倍时基本达到磁盘存取极限。由于上述原因,这也就是为什么FastCopy不使用系统缓存的缘故了。
当然如果大家有什么更好的看法或想法,欢迎留言探讨,谢谢!
- 寻找最快的大文件拷贝方法(转自:http://www.cnblogs.com/hesicong/archive/2007/08/18/860763.html)
- C#写文件常用的五种方法(转自:http://www.cnblogs.com/kiddo/archive/2008/03/17/1110061.html)
- 敏捷开发(转自:http://www.cnblogs.com/blusehuang/archive/2007/10/17/926802.html)
- C/C++ 笔试、面试题目大汇总,转自http://www.cnblogs.com/fangyukuan/archive/2010/09/18/1829871.html
- SqlServer 监控数据库连接数方法(转自:http://www.cnblogs.com/alphacn/archive/2010/07/19/1780572.html)
- c#的迭代器,转自http://www.cnblogs.com/yangecnu/archive/2012/03/17/2402432.html
- ACM基本输入输出(转自http://www.cnblogs.com/chenqiangjsj/archive/2011/04/08/2009452.html)
- 超链接按钮(转自http://www.cnblogs.com/cxy521/archive/2008/01/22/1048621.html)
- ListView应用(转自http://www.cnblogs.com/allin/archive/2010/05/11/1732200.html)
- tar命令(转自http://www.cnblogs.com/qq78292959/archive/2011/07/06/2099427.html)
- python 的日志logging模块学习 (转自:http://www.cnblogs.com/dkblog/archive/2011/08/26/2155018.html)
- 小白谈memcache和memcached的区别(转自:http://www.cnblogs.com/scotoma/archive/2011/02/15/1955573.html)
- xm create的过程 (转自http://www.cnblogs.com/feisky/archive/2012/01/17/2325018.html)
- IHttpModule.Init方法被执行多次的原因(转自:http://www.cnblogs.com/mingda/archive/2009/02/11/1388709.html)
- C# 启动外部程序的几种方法(转自:http://www.cnblogs.com/Slxj/archive/2012/01/12/2320531.html)
- SQL优化--使用分析函数(转自:http://www.cnblogs.com/zping/archive/2008/08/06/1261973.html)
- linux信号机制分析(转自http://www.cnblogs.com/hoys/archive/2012/08/19/2646377.html)
- Unicode字符编码规范(转自http://www.cnblogs.com/meil/archive/2007/02/01/636738.html)
- 企业网络营销KPI:转化率、跳出率、点击率 (CTR)
- 推荐引擎算法学习导论
- 编程语言的诞生与发展
- 关于lenovo笔记本新平台机型插拔电源适配器时主机“滴滴”报警的相关说明
- “本站已运行了多少天”代码(js版+php版)
- 寻找最快的大文件拷贝方法(转自:http://www.cnblogs.com/hesicong/archive/2007/08/18/860763.html)
- xxxxxxx
- Framework1
- Silverlight/WPF中的布局
- ZOJ3116 POJ3483 HDU1910 Loan Scheduling
- Framework2
- C# 启动外部程序的几种方法(转自:http://www.cnblogs.com/Slxj/archive/2012/01/12/2320531.html)
- hdu 2018
- ssh pub key on remote server