将文件从一个目录复制到另一个目录的最快方法
Fastest way to copy files from one directory to another
我需要将文件从一个目录复制到另一个目录,这取决于文件名在 SQL 数据库的 table 中是否存在。
为此,我使用以下代码:
using(SqlConnection connection = new SqlConnection("datasource or route"))
{
connection.Open();
using(SqlCommand cmd = new SqlCommand("SELECT idPic, namePicFile FROM DocPicFiles", connection))
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader != null)
{
while (reader.Read())
{
//picList IS AN ARRAY THAT Contains All the files names in a directory
if (picList.Any(s => s.Contains(reader["namePicFile"].ToString())))
{
File.Copy("theFile in the Directory or array picList", "the destiny directory"+ ".jpg", false)
}
}
}
}
}
有什么方法可以在更短的时间内完成吗?完成 20.876 条记录需要 1 小时。
File.Copy 是最快的速度。您必须记住,您取决于硬件规定的文件传输速度,在 20000 个文件时,数据访问的延迟也会发挥作用。如果您在 HDD 上执行此操作,则在切换到 SSD 或其他一些快速介质后会看到很大的改进。
仅就这种情况而言,硬件很可能是您的瓶颈。
编辑:我认为长时间保持与数据库的连接是一种不好的做法。我建议您在一些内存缓存(数组、列表等)中获取所有需要的数据,然后在复制文件时遍历这些数据。数据库连接是一种宝贵的资源,在必须处理高并发(但不仅如此)的应用程序上,必须快速释放连接。
请允许我猜一猜 - 嗯... 不。没有办法更快了。
我怎么这么自信?因为文件复制需要与磁盘对话,这是一个极其缓慢的操作。更进一步,如果您尝试使用多线程,结果将变得更慢而不是更快,因为在磁盘上移动磁头的 'mechanical' 操作不再是连续的,这可能是偶然的。
参见answers to this question I asked earlier。
是的,如果您还没有使用 SSD,请尝试使用它们,否则您已经获得了最好的。
下面是一些让我们了解 slow 与缓存相比在磁盘写入中意味着什么的东西。 如果缓存访问需要 10 分钟,这意味着从磁盘读取需要 2 年。所有访问如下图所示。很明显,当您的代码执行时,瓶颈将是磁盘写入。尽你所能让磁盘写入保持顺序。
由于您的 i/o 子系统几乎肯定是这里的瓶颈,因此使用并行任务库可能会达到最佳效果:
static void Main(string[] args)
{
DirectoryInfo source = new DirectoryInfo( args[0] ) ;
DirectoryInfo destination = new DirectoryInfo( args[1] ) ;
HashSet<string> filesToBeCopied = new HashSet<string>( ReadFileNamesFromDatabase() , StringComparer.OrdinalIgnoreCase ) ;
// you'll probably have to play with MaxDegreeOfParallellism so as to avoid swamping the i/o system
ParallelOptions options= new ParallelOptions { MaxDegreeOfParallelism = 4 } ;
Parallel.ForEach( filesToBeCopied.SelectMany( fn => source.EnumerateFiles( fn ) ) , options , fi => {
string destinationPath = Path.Combine( destination.FullName , Path.ChangeExtension( fi.Name , ".jpg") ) ;
fi.CopyTo( destinationPath , false ) ;
}) ;
}
public static IEnumerable<string> ReadFileNamesFromDatabase()
{
using ( SqlConnection connection = new SqlConnection( "connection-string" ) )
using ( SqlCommand cmd = connection.CreateCommand() )
{
cmd.CommandType = CommandType.Text ;
cmd.CommandText = @"
select idPic ,
namePicFile
from DocPicFiles
" ;
connection.Open() ;
using ( SqlDataReader reader = cmd.ExecuteReader() )
{
while ( reader.Read() )
{
yield return reader.GetString(1) ;
}
}
connection.Close() ;
}
}
我通过使用参数创建单个压缩文件 (.zip) 来解决此问题以仅存储文件(无压缩)。创建单个 (.zip) 文件,移动该单个文件,然后在该位置展开,在处理数千个文件时证明速度提高了 2 倍。
我需要将文件从一个目录复制到另一个目录,这取决于文件名在 SQL 数据库的 table 中是否存在。
为此,我使用以下代码:
using(SqlConnection connection = new SqlConnection("datasource or route"))
{
connection.Open();
using(SqlCommand cmd = new SqlCommand("SELECT idPic, namePicFile FROM DocPicFiles", connection))
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader != null)
{
while (reader.Read())
{
//picList IS AN ARRAY THAT Contains All the files names in a directory
if (picList.Any(s => s.Contains(reader["namePicFile"].ToString())))
{
File.Copy("theFile in the Directory or array picList", "the destiny directory"+ ".jpg", false)
}
}
}
}
}
有什么方法可以在更短的时间内完成吗?完成 20.876 条记录需要 1 小时。
File.Copy 是最快的速度。您必须记住,您取决于硬件规定的文件传输速度,在 20000 个文件时,数据访问的延迟也会发挥作用。如果您在 HDD 上执行此操作,则在切换到 SSD 或其他一些快速介质后会看到很大的改进。
仅就这种情况而言,硬件很可能是您的瓶颈。
编辑:我认为长时间保持与数据库的连接是一种不好的做法。我建议您在一些内存缓存(数组、列表等)中获取所有需要的数据,然后在复制文件时遍历这些数据。数据库连接是一种宝贵的资源,在必须处理高并发(但不仅如此)的应用程序上,必须快速释放连接。
请允许我猜一猜 - 嗯... 不。没有办法更快了。
我怎么这么自信?因为文件复制需要与磁盘对话,这是一个极其缓慢的操作。更进一步,如果您尝试使用多线程,结果将变得更慢而不是更快,因为在磁盘上移动磁头的 'mechanical' 操作不再是连续的,这可能是偶然的。
参见answers to this question I asked earlier。
是的,如果您还没有使用 SSD,请尝试使用它们,否则您已经获得了最好的。
下面是一些让我们了解 slow 与缓存相比在磁盘写入中意味着什么的东西。 如果缓存访问需要 10 分钟,这意味着从磁盘读取需要 2 年。所有访问如下图所示。很明显,当您的代码执行时,瓶颈将是磁盘写入。尽你所能让磁盘写入保持顺序。
由于您的 i/o 子系统几乎肯定是这里的瓶颈,因此使用并行任务库可能会达到最佳效果:
static void Main(string[] args)
{
DirectoryInfo source = new DirectoryInfo( args[0] ) ;
DirectoryInfo destination = new DirectoryInfo( args[1] ) ;
HashSet<string> filesToBeCopied = new HashSet<string>( ReadFileNamesFromDatabase() , StringComparer.OrdinalIgnoreCase ) ;
// you'll probably have to play with MaxDegreeOfParallellism so as to avoid swamping the i/o system
ParallelOptions options= new ParallelOptions { MaxDegreeOfParallelism = 4 } ;
Parallel.ForEach( filesToBeCopied.SelectMany( fn => source.EnumerateFiles( fn ) ) , options , fi => {
string destinationPath = Path.Combine( destination.FullName , Path.ChangeExtension( fi.Name , ".jpg") ) ;
fi.CopyTo( destinationPath , false ) ;
}) ;
}
public static IEnumerable<string> ReadFileNamesFromDatabase()
{
using ( SqlConnection connection = new SqlConnection( "connection-string" ) )
using ( SqlCommand cmd = connection.CreateCommand() )
{
cmd.CommandType = CommandType.Text ;
cmd.CommandText = @"
select idPic ,
namePicFile
from DocPicFiles
" ;
connection.Open() ;
using ( SqlDataReader reader = cmd.ExecuteReader() )
{
while ( reader.Read() )
{
yield return reader.GetString(1) ;
}
}
connection.Close() ;
}
}
我通过使用参数创建单个压缩文件 (.zip) 来解决此问题以仅存储文件(无压缩)。创建单个 (.zip) 文件,移动该单个文件,然后在该位置展开,在处理数千个文件时证明速度提高了 2 倍。