什么.NET类是SLOW与API? [英] What .NET classes are SLOW vs. API?

查看:69
本文介绍了什么.NET类是SLOW与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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆