什么.NET类是SLOW与API? [英] What .NET classes are SLOW vs. API?
问题描述
作为一个相当新的.NET编码器,我非常感谢
的任何评论。与
direct API相比,任何已知的.NET类都非常慢。打电话。
我已经在使用System.IO.DirectoryInfo时遇到了不好的经历。我的
要求是递归扫描文件夹,记录所有
文件名/日期/尺寸/属性。目标文件夹包含88,000
文件和5,000个子文件夹。
我最初使用System.IO.DirectoryInfo并发现它非常慢,
所以我尝试使用API FindFirst / FindNext做同样的事情。从IDE运行时,API版本
的速度提高了18倍*,并且在运行Release .exe时,* 5 * *次
更快。测试多次运行到
确保目录被缓存,因此磁盘访问时间不是
a因子。
这个我的应用程序不易受到影响,所以我正在写一个很好的课程
使用API启动目录列表
System.IO.DirectoryInfo'的屁股。
但是,如果善意的话,我宁愿避免不必要的
写/ wtf /重写/基准/修复周期
陌生人可以引导我清楚。 :)我只对那些可能被快速反复调用的类感兴趣,并且比API等价物慢得多b / b
;因此可能对
应用程序性能产生很大影响。
As a fairly new .NET coder, I would greatly appreciate some comments on
any .NET classes that are known to be notoriously slow by comparison to
direct API calls.
I''ve already had a bad experience with System.IO.DirectoryInfo. My
requirements were to recursively scan a folder, recording all
filenames/dates/sizes/attribs. The target folder contained 88,000
files and 5,000 subfolders.
I originally used System.IO.DirectoryInfo and found it incredibly slow,
so I tried the same thing with API FindFirst/FindNext. The API version
was *eighteen* times faster when run from the IDE, and *five* times
faster when running the Release .exe. Tests were run multiple times to
make sure the directories were cached, thus disk access times were not
a factor.
This was unacceptible for my application, so I''m writing a nice class
for directory listings using the API which kicks
System.IO.DirectoryInfo''s arse.
However, I would prefer to avoid needless
write/wtf/rewrite/benchmark/fix cycles in the future if the kindness of
strangers can steer me clear. :) I''m only interested in classes that
are likely to be called rapidly and repeatedly, and are much slower
than API equivalents; and so are likely to have a large impact on
application performance.
推荐答案
我认为你你觉得孩子很伤心。
也许你试图在阵列中存储88,000件物品?
给我们更多信息;我有一个类似的项目给出了相反的结果确切的
... .NET枚举的文件夹/文件比我在vb6中做的任何事情都要快一点br />
-Aaron
te******@hotmail.com 写道:
I think that you''re friggin whacked kid.
maybe you''re trying to store 88,000 items in an array?
give us more information; i have a similar project that gave the exact
opposite results... .NET enumerating of folders / files was quite a
bit faster than anything i could do in vb6
-Aaron
te******@hotmail.com wrote:
作为一个相当新的.NET编码器,我非常感谢
的任何评论,因为众所周知的.NET类很慢与
直接API调用相比。
我已经在使用System.IO.DirectoryInfo时遇到了不好的经历。我的
要求是递归扫描文件夹,记录所有
文件名/日期/尺寸/属性。目标文件夹包含88,000
文件和5,000个子文件夹。
我最初使用System.IO.DirectoryInfo并发现它非常慢,
所以我尝试使用API FindFirst / FindNext做同样的事情。从IDE运行时,API版本
的速度提高了18倍*,并且在运行Release .exe时,* 5 * *次
更快。测试多次运行到
确保目录被缓存,因此磁盘访问时间不是
a因子。
这个我的应用程序不易受到影响,所以我正在写一个很好的课程
使用API启动目录列表
System.IO.DirectoryInfo'的屁股。
但是,如果善意的话,我宁愿避免不必要的
写/ wtf /重写/基准/修复周期
陌生人可以引导我清楚。 :)我只对那些可能被快速反复调用的类感兴趣,并且比API等价物慢得多b / b
;因此可能对
应用程序性能产生很大影响。
As a fairly new .NET coder, I would greatly appreciate some comments on
any .NET classes that are known to be notoriously slow by comparison to
direct API calls.
I''ve already had a bad experience with System.IO.DirectoryInfo. My
requirements were to recursively scan a folder, recording all
filenames/dates/sizes/attribs. The target folder contained 88,000
files and 5,000 subfolders.
I originally used System.IO.DirectoryInfo and found it incredibly slow,
so I tried the same thing with API FindFirst/FindNext. The API version
was *eighteen* times faster when run from the IDE, and *five* times
faster when running the Release .exe. Tests were run multiple times to
make sure the directories were cached, thus disk access times were not
a factor.
This was unacceptible for my application, so I''m writing a nice class
for directory listings using the API which kicks
System.IO.DirectoryInfo''s arse.
However, I would prefer to avoid needless
write/wtf/rewrite/benchmark/fix cycles in the future if the kindness of
strangers can steer me clear. :) I''m only interested in classes that
are likely to be called rapidly and repeatedly, and are much slower
than API equivalents; and so are likely to have a large impact on
application performance.
aa ******* **@gmail.com 写道:
我认为你是个傻瓜孩子。
I think that you''re friggin whacked kid.
嗯,这不是我希望的那种有用的回应。
但是让我们滚动吧,我等待其他人回答我的
问题。
Erm, that''s not exactly the kind of useful response I was hoping for.
But let''s roll with it, while I wait for anyone else to answer my
question.
也许你试图在阵列中存储88,000个项目?
maybe you''re trying to store 88,000 items in an array?
呃,没有。那是相当愚蠢的。
Erm, no. That''s rather silly.
给我们更多信息;我有一个类似的项目给出了确切的
相反的结果...... .NET枚举的文件夹/文件比我在vb6 $中做的任何事情都要快得多b $ b
give us more information; i have a similar project that gave the exact
opposite results... .NET enumerating of folders / files was quite a
bit faster than anything i could do in vb6
VB6在这个部门也不是那么好。这就是为什么我学会了
首先使用API。
按照目前的配置,测试程序递归扫描整个
C:开车,计算文件和目录。它还抓住了它遇到的每个文件/目录的大小,属性,
和所有三个时间戳,并将它们存储在一个可以用于生产效率的结构中的
,但是在
这个案子被迅速丢弃。我这样做只是为了确保实际读取
信息。使用了两种方法,即
System.IO.DirectoryInfo和API调用。我确保两个版本中可能的两个版本相似,因此在.NET / API调用中,唯一可靠的时间差异是
。
我也*忽略*第一次运行,因为它受到了惩罚 -
目录信息实际上是从磁盘读取的。在那之后,它是缓存的
;假设你的内存足够大而你的驱动器足够小。
顺便说一句,我的C:驱动器在16,784个文件夹中有240,295个文件。我从.NET 2.0 IDE和Release .exe运行了
测试,结果如下:
结果:
System.IO.DirectoryInfo,从IDE运行:80,734毫秒(毫秒)
System.IO.DirectoryInfo,Release .exe:43,471 ms
Windows API,从IDE:5,812 ms
Windows API,Release .exe:4,047 ms
这些结果甚至比我最初的结果更差。但是在这一点上,
对我来说并不重要*如何*可笑地放慢它的速度 - 它的价格仍然非常慢。使用
..NET方法(无论如何只调用API)比预期更多的开销,并且对于我计划的
使用次数是不可接受的。 />
我邀请你自己尝试一下,得到自己的结果,并得出你自己的结论。让我知道它们是什么。
创建一个新项目,向表单添加两个按钮,删除现有代码,
并将其粘贴到(表out for wordwrap):
-----
进口System.Runtime.InteropServices
Public Class Form1
Private Const INVALID_HANDLE_VALUE As Integer = -1
Private Const MAX_PATH As Integer = 260
结构tFILETIME
Dim dwLowDateTime作为Int32
Dim dwHighDateTime作为Int32
结束结构
< StructLayout(LayoutKind.Sequential, CharSet:= CharSet.Ansi)_
私有结构WIN32_FIND_DATA
公共dwFileAttributes为整数
公共ftCreationTime as tFILETIME
公共ftLastAccessTime as tFILETIME
公共ftLastWriteTime as tFILETIME
Public nFileSizeHigh As UInt32
Public nFileSizeLow As UInt32
Public dwReserved0 As Int32
Public dwReser ved1 As Int32
< MarshalAs(UnmanagedType.ByValTStr,SizeConst:= MAX_PATH)_
Public cFileName As String
< MarshalAs(UnmanagedType .ByValTStr,SizeConst:= 14)_
Public cAlternateFileName As String
结束结构
私有声明函数FindFirstFile Lib" kernel32" Alias
" FindFirstFileA" (ByVal lpFileName As String,ByRef lpFindFileData As
WIN32_FIND_DATA)As Int32
私有声明函数FindNextFile Lib" kernel32" Alias
" FindNextFileA" (ByVal hFindFile As Int32,ByRef lpFindFileData As
WIN32_FIND_DATA)As Int32
私有声明函数FindClose Lib" kernel32" (ByVal hFindFile As
Int32)作为Int32
公共结构DirItem
Dim Name As String
Dim Size As Long
Dim Attribs As System.IO.FileAttributes
Dim DateAccessed As Date
Dim DateCreated As Date
昏暗日期修改为日期
结束结构
昏暗文件,Dirs为整数
私有子按钮1_Click (ByVal sender As System.Object,ByVal e As
System.EventArgs)处理Button1.Click
测试(1)
结束Sub
Private Sub Button2_Click(ByVal sender As System.Object,ByVal e As
System.EventArgs)处理Button2.Click
测试(2)
结束子
子测试(ByVal方法为整数)
Dim StartTick As Integer = My.Computer。 Clock.TickCount
Files = 0
Dirs = 0
选择案例方法
案例1:RecurseDirsNet(& ; c:")
案例2:RecurseDirsAPI (c:)
结束选择
MsgBox(" Files =" &安培;档案& vbCrLf& Dirs = &安培; Dirs& vbCrLf&
" Time(ms)=" &安培; (My.Computer.Clock.TickCount - StartTick))
End Sub
Public Sub RecurseDirsAPI(ByVal Path As String)
Dim s1 As String
Dim WFD As New WIN32_FIND_DATA
Dim x As DirItem
Dim hDir As Integer = FindFirstFile(Path&" \ *。*",WFD)
如果hDir = INVALID_HANDLE_VALUE则停止
请
x =新DirItem
s1 = StripNull(WFD.cFileName)
如果s1<"。并且s1 <...然后
随x
.Name = s1
.Size = WFD.nFileSizeLow + WFD.nFileSizeHigh * 4294967296
.Attribs = WFD.dwFileAttributes
.DateAccessed = FileTimeConvert(WFD.ftLastAccessTime)
.DateCreated = FileTimeConvert(WFD.ftCreationTime)
。 DateModified = FileTimeConvert(WFD.ftLastWriteTime)
如果.Attribs和IO.FileAttributes.Directory那么
Dirs + = 1
RecurseDirsAPI(Path& ;" \"& .Name)
否则
档案+ = 1
结束如果
结束
结束如果
如果FindNextFile(hDir,WFD)= 0则退出Do
循环
FindClose(hDir)
End Sub
Public Sub RecurseDirsNet(按字符串的ByVal路径)
Dim x As DirItem
Dim DI As New System.IO.DirectoryInfo(Path&" \")
For Each File AsIO.FileInfo in DI.GetFiles
x =新DirItem
随x
.Name = File.Name
.Attribs = File.Attributes
.DateAccessed = File.LastAccessTime
.DateCreated = File.CreationTime
。日期修改= File.LastWriteTime
结束
文件+ = 1
下一页
对于每个Dir As System.IO.DirectoryInfo在DI.GetDirectories
x = New DirItem
with x
.Name = Dir.Name
.Attribs = Dir.Attributes
.DateAccessed = Dir.LastAccessTime
.DateCreated = Dir.CreationTime
。 DateModified = Dir.LastWriteTime
Dirs + = 1
RecurseDirsNet(Path& " \" &安培; .Name)
结束
下一页
结束子
功能StripNull(ByVal X As String)As String
Dim l1 As Long:l1 = InStr(1,X,Chr(0),vbBinaryCompare)
如果l1 = 0那么
StripNull = X
否则
StripNull = Strings.Left(X,l1 - 1)
结束如果
结束函数
私有函数FileTimeConvert(ByVal udtFileTime as tFILETIME)作为
日期
FileTimeConvert =
System.DateTime.FromFileTime(udtFileTime.dwLowDate时间+
udtFileTime.dwHighDateTime * 4294967296)
结束功能
结束类
VB6 wasn''t so great in this department either. That''s why I learned to
use the API in the first place.
As currently configured, the test program recursively scans the entire
C: drive, counting files and dirs. It also grabs the size, attribs,
and all three timestamps of each file/dir it encounters and stores them
in a structure which could be used for something productive, but in
this case is promptly discarded. I do it only to make sure the
information is actually read. Two methods are used, the
System.IO.DirectoryInfo, and API calls. I made sure as much as
possible is similar in the two versions, so that the only substantial
time difference is in the .NET/API call.
I also *disregard* the first run, as it suffers a penalty - the
directory info is actually being read from the disk. After that, it''s
cached; assuming your memory is big enough and your drive small enough.
By the way, my C: drive has 240,295 files in 16,784 folders. I ran the
test both from the .NET 2.0 IDE and from the Release .exe, and here are
the results:
System.IO.DirectoryInfo, run from IDE: 80,734 ms (milliseconds)
System.IO.DirectoryInfo, Release .exe: 43,671 ms
Windows API, run from IDE: 5,812 ms
Windows API, Release .exe: 4,047 ms
These results are even worse than my initial ones. But at this point,
it doesn''t really matter to me *how* ridiculously slow it is - it''s
still ridiculously slow. Way more overhead than expected for using the
..NET method (which just calls the API anyway), and unacceptable for a
number of uses I have planned.
I invite you to try this yourself, get your own results, and draw your
own conclusions. And let me know what they are.
Create a new project, add two buttons to a form, delete existing code,
and paste this in (watch out for wordwrap):
-----
Imports System.Runtime.InteropServices
Public Class Form1
Private Const INVALID_HANDLE_VALUE As Integer = -1
Private Const MAX_PATH As Integer = 260
Structure tFILETIME
Dim dwLowDateTime As Int32
Dim dwHighDateTime As Int32
End Structure
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)_
Private Structure WIN32_FIND_DATA
Public dwFileAttributes As Integer
Public ftCreationTime As tFILETIME
Public ftLastAccessTime As tFILETIME
Public ftLastWriteTime As tFILETIME
Public nFileSizeHigh As UInt32
Public nFileSizeLow As UInt32
Public dwReserved0 As Int32
Public dwReserved1 As Int32
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=MAX_PATH)_
Public cFileName As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=14)_
Public cAlternateFileName As String
End Structure
Private Declare Function FindFirstFile Lib "kernel32" Alias
"FindFirstFileA" (ByVal lpFileName As String, ByRef lpFindFileData As
WIN32_FIND_DATA) As Int32
Private Declare Function FindNextFile Lib "kernel32" Alias
"FindNextFileA" (ByVal hFindFile As Int32, ByRef lpFindFileData As
WIN32_FIND_DATA) As Int32
Private Declare Function FindClose Lib "kernel32" (ByVal hFindFile As
Int32) As Int32
Public Structure DirItem
Dim Name As String
Dim Size As Long
Dim Attribs As System.IO.FileAttributes
Dim DateAccessed As Date
Dim DateCreated As Date
Dim DateModified As Date
End Structure
Dim Files, Dirs As Integer
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Test(1)
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
Test(2)
End Sub
Sub Test(ByVal Method As Integer)
Dim StartTick As Integer = My.Computer.Clock.TickCount
Files = 0
Dirs = 0
Select Case Method
Case 1 : RecurseDirsNet("c:")
Case 2 : RecurseDirsAPI("c:")
End Select
MsgBox("Files = " & Files & vbCrLf & "Dirs = " & Dirs & vbCrLf &
"Time (ms)= " & (My.Computer.Clock.TickCount - StartTick))
End Sub
Public Sub RecurseDirsAPI(ByVal Path As String)
Dim s1 As String
Dim WFD As New WIN32_FIND_DATA
Dim x As DirItem
Dim hDir As Integer = FindFirstFile(Path & "\*.*", WFD)
If hDir = INVALID_HANDLE_VALUE Then Stop
Do
x = New DirItem
s1 = StripNull(WFD.cFileName)
If s1 <"." And s1 <".." Then
With x
.Name = s1
.Size = WFD.nFileSizeLow + WFD.nFileSizeHigh * 4294967296
.Attribs = WFD.dwFileAttributes
.DateAccessed = FileTimeConvert(WFD.ftLastAccessTime)
.DateCreated = FileTimeConvert(WFD.ftCreationTime)
.DateModified = FileTimeConvert(WFD.ftLastWriteTime)
If .Attribs And IO.FileAttributes.Directory Then
Dirs += 1
RecurseDirsAPI(Path & "\" & .Name)
Else
Files += 1
End If
End With
End If
If FindNextFile(hDir, WFD) = 0 Then Exit Do
Loop
FindClose(hDir)
End Sub
Public Sub RecurseDirsNet(ByVal Path As String)
Dim x As DirItem
Dim DI As New System.IO.DirectoryInfo(Path & "\")
For Each File As System.IO.FileInfo In DI.GetFiles
x = New DirItem
With x
.Name = File.Name
.Attribs = File.Attributes
.DateAccessed = File.LastAccessTime
.DateCreated = File.CreationTime
.DateModified = File.LastWriteTime
End With
Files += 1
Next
For Each Dir As System.IO.DirectoryInfo In DI.GetDirectories
x = New DirItem
With x
.Name = Dir.Name
.Attribs = Dir.Attributes
.DateAccessed = Dir.LastAccessTime
.DateCreated = Dir.CreationTime
.DateModified = Dir.LastWriteTime
Dirs += 1
RecurseDirsNet(Path & "\" & .Name)
End With
Next
End Sub
Function StripNull(ByVal X As String) As String
Dim l1 As Long : l1 = InStr(1, X, Chr(0), vbBinaryCompare)
If l1 = 0 Then
StripNull = X
Else
StripNull = Strings.Left(X, l1 - 1)
End If
End Function
Private Function FileTimeConvert(ByVal udtFileTime As tFILETIME) As
Date
FileTimeConvert =
System.DateTime.FromFileTime(udtFileTime.dwLowDate Time +
udtFileTime.dwHighDateTime * 4294967296)
End Function
End Class
什么..你不能从vb6调用API?对不起,我暗示
我很快就会发布一些类似的代码好吧
-aaron
te ****** @ hotmail.com 写道:
what.. you can''t call an API from vb6? sorry i implied that
i''ll post some of my similiar code soon ok
-aaron
te******@hotmail.com wrote:
aa ********* @ gmail.com 写道:
我认为你是个傻瓜孩子。
I think that you''re friggin whacked kid.
嗯,这不是我希望的那种有用的回应。
但是让我们滚动吧,我等待其他人回答我的
问题。
Erm, that''s not exactly the kind of useful response I was hoping for.
But let''s roll with it, while I wait for anyone else to answer my
question.
也许你试图在阵列中存储88,000个项目?
maybe you''re trying to store 88,000 items in an array?
嗯,没有。那是相当愚蠢的。
Erm, no. That''s rather silly.
给我们更多信息;我有一个类似的项目给出了确切的
相反的结果...... .NET枚举的文件夹/文件比我在vb6 $中做的任何事情都要快得多b $ b
give us more information; i have a similar project that gave the exact
opposite results... .NET enumerating of folders / files was quite a
bit faster than anything i could do in vb6
VB6在这个部门也不是那么好。这就是为什么我学会了
首先使用API。
按照目前的配置,测试程序递归扫描整个
C:开车,计算文件和目录。它还抓住了它遇到的每个文件/目录的大小,属性,
和所有三个时间戳,并将它们存储在一个可以用于生产效率的结构中的
,但是在
这个案子被迅速丢弃。我这样做只是为了确保实际读取
信息。使用了两种方法,即
System.IO.DirectoryInfo和API调用。我确保两个版本中可能的两个版本相似,因此在.NET / API调用中,唯一可靠的时间差异是
。
我也*忽略*第一次运行,因为它受到了惩罚 -
目录信息实际上是从磁盘读取的。在那之后,它是缓存的
;假设你的内存足够大而你的驱动器足够小。
顺便说一句,我的C:驱动器在16,784个文件夹中有240,295个文件。我从.NET 2.0 IDE和Release .exe运行了
测试,结果如下:
结果:
System.IO.DirectoryInfo,从IDE运行:80,734毫秒(毫秒)
System.IO.DirectoryInfo,Release .exe:43,471 ms
Windows API,从IDE:5,812 ms
Windows API,Release .exe:4,047 ms
这些结果甚至比我最初的结果更差。但是在这一点上,
对我来说并不重要*如何*可笑地放慢它的速度 - 它的价格仍然非常慢。使用
.NET方法(无论如何只调用API)的开销比预期的要多,而且我计划的
使用次数是不可接受的。
我邀请您自己尝试,获得自己的结果,并得出您自己的结论。让我知道它们是什么。
创建一个新项目,向表单添加两个按钮,删除现有代码,
并将其粘贴到(表out for wordwrap):
-----
进口System.Runtime.InteropServices
Public Class Form1
Private Const INVALID_HANDLE_VALUE As Integer = -1
Private Const MAX_PATH As Integer = 260
结构tFILETIME
Dim dwLowDateTime作为Int32
Dim dwHighDateTime作为Int32
结束结构
< StructLayout(LayoutKind.Sequential, CharSet:= CharSet.Ansi)_
私有结构WIN32_FIND_DATA
公共dwFileAttributes为整数
公共ftCreationTime as tFILETIME
公共ftLastAccessTime as tFILETIME
公共ftLastWriteTime as tFILETIME
Public nFileSizeHigh As UInt32
Public nFileSizeLow As UInt32
Public DW Reserved0 As Int32
Public dwReserved1 As Int32
< MarshalAs(UnmanagedType.ByValTStr,SizeConst:= MAX_PATH)_
Public cFileName As String
< MarshalAs(UnmanagedType.ByValTStr,SizeConst:= 14)_
Public cAlternateFileName As String
结束结构
私有声明函数FindFirstFile Lib" kernel32" Alias
" FindFirstFileA" (ByVal lpFileName As String,ByRef lpFindFileData As
WIN32_FIND_DATA)As Int32
私有声明函数FindNextFile Lib" kernel32" Alias
" FindNextFileA" (ByVal hFindFile As Int32,ByRef lpFindFileData As
WIN32_FIND_DATA)As Int32
私有声明函数FindClose Lib" kernel32" (ByVal hFindFile As
Int32)作为Int32
公共结构DirItem
Dim Name As String
Dim Size As Long
Dim Attribs As System.IO.FileAttributes
Dim DateAccessed As Date
Dim DateCreated As Date
昏暗日期修改为日期
结束结构
昏暗文件,Dirs为整数
私有子按钮1_Click (ByVal sender As System.Object,ByVal e As
System.EventArgs)处理Button1.Click
测试(1)
结束Sub
Private Sub Button2_Click(ByVal sender As System.Object,ByVal e As
System.EventArgs)处理Button2.Click
测试(2)
结束子
子测试(ByVal方法为整数)
Dim StartTick As Integer = My.Computer。 Clock.TickCount
Files = 0
Dirs = 0
选择案例方法
案例1: RecurseDirsNet(" c:")
案例2:RecurseDirsAPI(" c:")
结束选择
MsgBox(& ; Files =" &安培;档案& vbCrLf& Dirs = &安培; Dirs& vbCrLf&
" Time(ms)=" &安培; (My.Computer.Clock.TickCount - StartTick))
End Sub
Public Sub RecurseDirsAPI(ByVal Path As String)
Dim s1 As String
Dim WFD As New WIN32_FIND_DATA
Dim x As DirItem
Dim hDir As Integer = FindFirstFile(Path&" \ *。*",WFD)
如果hDir = INVALID_HANDLE_VALUE则停止
请
x =新DirItem
s1 = StripNull(WFD.cFileName)
如果s1<"。并且s1 <...然后
随x
.Name = s1
.Size = WFD.nFileSizeLow + WFD.nFileSizeHigh * 4294967296
.Attribs = WFD.dwFileAttributes
.DateAccessed = FileTimeConvert(WFD.ftLastAccessTime)
.DateCreated = FileTimeConvert(WFD.ftCreationTime)
。 DateModified = FileTimeConvert(WFD.ftLastWriteTime)
如果.Attribs和IO.FileAttributes.Directory那么
Dirs + = 1
RecurseDirsAPI(Path& ;" \"& .Name)
否则
档案+ = 1
结束如果
结束
结束如果
如果FindNextFile(hDir,WFD)= 0则退出Do
循环
FindClose(hDir)
End Sub
Public Sub RecurseDirsNet(按字符串的ByVal路径)
Dim x As DirItem
Dim DI As New System.IO.DirectoryInfo(Path& " \")
每个文件作为System.IO.FileInfo在DI.GetFiles中
x =新DirItem
随x
.Name = File.Name
.Attribs = File.Attributes
.DateAccessed = File.LastAccessTime
。 DateCreated = File.CreationTime
。日期修改= File.LastWriteTime
结束
文件+ = 1
下一页
每个目录为System.IO.DirectoryInfo在DI.GetDirectories
x =新DirItem
随x
.Name = Dir.Name
.Attribs = Dir.Attributes
。日期答案= Dir.LastAccessTime
.DateCreated = Dir.CreationTime
.DateModified = Dir.LastWriteTime
Dirs + = 1
RecurseDirsNet(Path&" \"& .Name)
结束
下一页
En d sub
函数StripNull(ByVal X As String)As String
Dim l1 As Long:l1 = InStr(1,X,Chr(0), vbBinaryCompare)
如果l1 = 0那么
StripNull = X
否则
StripNull = Strings.Left(X ,l1 - 1)
结束如果
结束功能
私有函数FileTimeConvert(ByVal udtFileTime as tFILETIME)As
日期
FileTimeConvert =
System.DateTime.FromFileTime(udtFileTime.dwLowDate时间+
udtFileTime.dwHighDateTime * 4294967296)
结束功能
结束班
VB6 wasn''t so great in this department either. That''s why I learned to
use the API in the first place.
As currently configured, the test program recursively scans the entire
C: drive, counting files and dirs. It also grabs the size, attribs,
and all three timestamps of each file/dir it encounters and stores them
in a structure which could be used for something productive, but in
this case is promptly discarded. I do it only to make sure the
information is actually read. Two methods are used, the
System.IO.DirectoryInfo, and API calls. I made sure as much as
possible is similar in the two versions, so that the only substantial
time difference is in the .NET/API call.
I also *disregard* the first run, as it suffers a penalty - the
directory info is actually being read from the disk. After that, it''s
cached; assuming your memory is big enough and your drive small enough.
By the way, my C: drive has 240,295 files in 16,784 folders. I ran the
test both from the .NET 2.0 IDE and from the Release .exe, and here are
the results:
System.IO.DirectoryInfo, run from IDE: 80,734 ms (milliseconds)
System.IO.DirectoryInfo, Release .exe: 43,671 ms
Windows API, run from IDE: 5,812 ms
Windows API, Release .exe: 4,047 ms
These results are even worse than my initial ones. But at this point,
it doesn''t really matter to me *how* ridiculously slow it is - it''s
still ridiculously slow. Way more overhead than expected for using the
.NET method (which just calls the API anyway), and unacceptable for a
number of uses I have planned.
I invite you to try this yourself, get your own results, and draw your
own conclusions. And let me know what they are.
Create a new project, add two buttons to a form, delete existing code,
and paste this in (watch out for wordwrap):
-----
Imports System.Runtime.InteropServices
Public Class Form1
Private Const INVALID_HANDLE_VALUE As Integer = -1
Private Const MAX_PATH As Integer = 260
Structure tFILETIME
Dim dwLowDateTime As Int32
Dim dwHighDateTime As Int32
End Structure
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)_
Private Structure WIN32_FIND_DATA
Public dwFileAttributes As Integer
Public ftCreationTime As tFILETIME
Public ftLastAccessTime As tFILETIME
Public ftLastWriteTime As tFILETIME
Public nFileSizeHigh As UInt32
Public nFileSizeLow As UInt32
Public dwReserved0 As Int32
Public dwReserved1 As Int32
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=MAX_PATH)_
Public cFileName As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=14)_
Public cAlternateFileName As String
End Structure
Private Declare Function FindFirstFile Lib "kernel32" Alias
"FindFirstFileA" (ByVal lpFileName As String, ByRef lpFindFileData As
WIN32_FIND_DATA) As Int32
Private Declare Function FindNextFile Lib "kernel32" Alias
"FindNextFileA" (ByVal hFindFile As Int32, ByRef lpFindFileData As
WIN32_FIND_DATA) As Int32
Private Declare Function FindClose Lib "kernel32" (ByVal hFindFile As
Int32) As Int32
Public Structure DirItem
Dim Name As String
Dim Size As Long
Dim Attribs As System.IO.FileAttributes
Dim DateAccessed As Date
Dim DateCreated As Date
Dim DateModified As Date
End Structure
Dim Files, Dirs As Integer
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Test(1)
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
Test(2)
End Sub
Sub Test(ByVal Method As Integer)
Dim StartTick As Integer = My.Computer.Clock.TickCount
Files = 0
Dirs = 0
Select Case Method
Case 1 : RecurseDirsNet("c:")
Case 2 : RecurseDirsAPI("c:")
End Select
MsgBox("Files = " & Files & vbCrLf & "Dirs = " & Dirs & vbCrLf &
"Time (ms)= " & (My.Computer.Clock.TickCount - StartTick))
End Sub
Public Sub RecurseDirsAPI(ByVal Path As String)
Dim s1 As String
Dim WFD As New WIN32_FIND_DATA
Dim x As DirItem
Dim hDir As Integer = FindFirstFile(Path & "\*.*", WFD)
If hDir = INVALID_HANDLE_VALUE Then Stop
Do
x = New DirItem
s1 = StripNull(WFD.cFileName)
If s1 <"." And s1 <".." Then
With x
.Name = s1
.Size = WFD.nFileSizeLow + WFD.nFileSizeHigh * 4294967296
.Attribs = WFD.dwFileAttributes
.DateAccessed = FileTimeConvert(WFD.ftLastAccessTime)
.DateCreated = FileTimeConvert(WFD.ftCreationTime)
.DateModified = FileTimeConvert(WFD.ftLastWriteTime)
If .Attribs And IO.FileAttributes.Directory Then
Dirs += 1
RecurseDirsAPI(Path & "\" & .Name)
Else
Files += 1
End If
End With
End If
If FindNextFile(hDir, WFD) = 0 Then Exit Do
Loop
FindClose(hDir)
End Sub
Public Sub RecurseDirsNet(ByVal Path As String)
Dim x As DirItem
Dim DI As New System.IO.DirectoryInfo(Path & "\")
For Each File As System.IO.FileInfo In DI.GetFiles
x = New DirItem
With x
.Name = File.Name
.Attribs = File.Attributes
.DateAccessed = File.LastAccessTime
.DateCreated = File.CreationTime
.DateModified = File.LastWriteTime
End With
Files += 1
Next
For Each Dir As System.IO.DirectoryInfo In DI.GetDirectories
x = New DirItem
With x
.Name = Dir.Name
.Attribs = Dir.Attributes
.DateAccessed = Dir.LastAccessTime
.DateCreated = Dir.CreationTime
.DateModified = Dir.LastWriteTime
Dirs += 1
RecurseDirsNet(Path & "\" & .Name)
End With
Next
End Sub
Function StripNull(ByVal X As String) As String
Dim l1 As Long : l1 = InStr(1, X, Chr(0), vbBinaryCompare)
If l1 = 0 Then
StripNull = X
Else
StripNull = Strings.Left(X, l1 - 1)
End If
End Function
Private Function FileTimeConvert(ByVal udtFileTime As tFILETIME) As
Date
FileTimeConvert =
System.DateTime.FromFileTime(udtFileTime.dwLowDate Time +
udtFileTime.dwHighDateTime * 4294967296)
End Function
End Class
这篇关于什么.NET类是SLOW与API?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!