____________________________________________致歉声明:以前在这里回答过关于按行读文本文件的问题,
我可能有误导的言论,在此向被我误导的朋友致歉
____________________________________________我一直想当然的认为分行读效率不如整个读到一个字符串然后再按换行符split到数组效率高但是在.NET区被高手指正我的说法是错误的
http://community.csdn.net/Expert/topic/4821/4821206.xml
我不知道在VB6中是不是与.NET中一样,我这里没有VB6环境,希望有VB6的朋友帮我测试一下,以解除我的疑惑,先谢了~
我可能有误导的言论,在此向被我误导的朋友致歉
____________________________________________我一直想当然的认为分行读效率不如整个读到一个字符串然后再按换行符split到数组效率高但是在.NET区被高手指正我的说法是错误的
http://community.csdn.net/Expert/topic/4821/4821206.xml
我不知道在VB6中是不是与.NET中一样,我这里没有VB6环境,希望有VB6的朋友帮我测试一下,以解除我的疑惑,先谢了~
在FSO对象里READALL是最慢的其次是READLINE,最好的是先确定文件长度然后READ(SIZE),但考虑到文件太大会造成内存不足,所以READLINE应该是最优的。
Dim b() As Byte, ttime As Single, temp As String, i As Long, fso As New FileSystemObject, ts As TextStream
ttime = Timer
Select Case indexCase 1
Open filename For Binary As #1
ReDim b(LOF(1))
Get #1, , b
Close #1
x = Split(StrConv(b, vbUnicode), vbCrLf)
Case 2
Open filename For Binary As #1
temp = Space(LOF(1))
Get #1, , temp
Close #1
x = Split(temp, vbCrLf)Case 3
Open filename For Input As #1
temp = StrConv(InputB(LOF(1), 1), vbUnicode)
Close #1
x = Split(temp, vbCrLf)Case 4
ReDim x(0)
Open filename For Input As #1
Do While Not EOF(1)
Line Input #1, x(i)
i = i + 1
ReDim Preserve x(i)
Loop
Close #1Case 5
Set ts = fso.OpenTextFile(filename)
temp = ts.ReadAll
x = Split(temp, vbCrLf)
ts.CloseCase 6
ReDim x(0)
Set ts = fso.OpenTextFile(filename)
Do While Not ts.AtEndOfStream
x(i) = ts.ReadLine
i = i + 1
ReDim Preserve x(i)
Loop
ts.Close
End Selecttimereadfiletoarray = "文件" & filename & "大小" & FileLen(filename) & "bytes,使用方法" & index & "赋值到数组X()用时" & Format(Timer - ttime, "0.0000") & "秒!"End FunctionPrivate Sub Command1_Click()
Text1.Text = ""
Dim i As Integer, j As Integer, x() As String
For j = 1 To 3
For i = 1 To 6
Debug.Print timereadfiletoarray(1, "e:\" & j & ".txt", x)
Next
Debug.Print
Next
End Sub测试结果如下:'文件e:\1.txt大小566890bytes,使用方法1赋值到数组X()用时0.0781秒!
'文件e:\1.txt大小566890bytes,使用方法2赋值到数组X()用时0.0469秒!
'文件e:\1.txt大小566890bytes,使用方法3赋值到数组X()用时0.0469秒!
'文件e:\1.txt大小566890bytes,使用方法4赋值到数组X()用时0.0625秒!
'文件e:\1.txt大小566890bytes,使用方法5赋值到数组X()用时0.2656秒!
'文件e:\1.txt大小566890bytes,使用方法6赋值到数组X()用时0.0781秒!'文件e:\2.txt大小4348798bytes,使用方法1赋值到数组X()用时1.4688秒!
'文件e:\2.txt大小4348798bytes,使用方法2赋值到数组X()用时1.6719秒!
'文件e:\2.txt大小4348798bytes,使用方法3赋值到数组X()用时1.7656秒!
'文件e:\2.txt大小4348798bytes,使用方法4赋值到数组X()用时2.8125秒!
'文件e:\2.txt大小4348798bytes,使用方法5赋值到数组X()用时1.8594秒!
''文件e:\2.txt大小4348798bytes,使用方法6赋值到数组X()用时2.8906秒!
'
'文件e:\3.txt大小43488140bytes,使用方法1赋值到数组X()用时237.9531秒!
'文件e:\3.txt大小43488140bytes,使用方法2赋值到数组X()用时311.9688秒!
'文件e:\3.txt大小43488140bytes,使用方法3赋值到数组X()用时302.0469秒!
'文件e:\3.txt大小43488140bytes,使用方法4赋值到数组X()用时31.4531秒!
'文件e:\3.txt大小43488140bytes,使用方法5赋值到数组X()用时189.0313秒!
'文件e:\3.txt大小43488140bytes,使用方法6赋值到数组X()用时47.1719秒!
超级大的文件,在耗尽内存的情况下(用虚拟内存了)速度自然超级慢。(猜测:即使内存没有耗尽,如果受到VB规格限制(堆、栈都有大小限制),也不得不使用虚拟内存。)
如果大文件耗尽物理内存了,那么这种比较就不合理了。我本人还是比较倾向于一次读入然后再split的。
我电脑上测试结果如下(已经关闭诺盾文件监视):
行写2字符5W行 47.0000
行写200字符5W行 390.0000
字写2字符5W行 31.0000
字写200字符5W行 735.0000这里读的文件大小是相同的,用行输出得到的文本:L10000S258L---9,100,000字节
行读200字符5W行 437.0000
字读200字符5W行 141.0000这里读的文件大小是相同的,用字节输出得到的文本:L10000S258B.txt---36,400,004字节
行读200字符5W行 437.0000
字读200字符5W行 485.0000提供我的测试代码:(写的比较匆忙,将就看吧,不过应该不是很难懂)'测试请建立一个窗体,需要一个按钮,名称默认
Option Explicit
Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Const mStrI = "12"
Private Const mStrL = "123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890"
Dim mByte() As Long
Dim tTime As Long
Dim mStr As String
Private Sub Command1_Click()
Dim i As Long
Debug.Print
killfile
'以下写的文件大小不同
tTime = GetTickCount
'行写2字符1W行
Open "c:\L10000S2L.txt" For Output As #1
For i = 0 To 49999
Print #1, mStrI
Next
Close #1
Debug.Print "行写2字符5W行 ", Format(GetTickCount - tTime, "0.0000")
DoEvents
tTime = GetTickCount
'行写200字符1W行
Open "c:\L10000S258L.txt" For Output As #1
For i = 0 To 49999
Print #1, mStrL
Next
Close #1
Debug.Print "行写200字符5W行", Format(GetTickCount - tTime, "0.0000")'读
Open "c:\L10000S2L.txt" For Binary As #1
ReDim mByte(LOF(1))
Get #1, , mByte
Close #1
DoEvents
tTime = GetTickCount
'字写2字符1W行
Open "c:\L10000S2B.txt" For Binary As #1
Put #1, , mByte
Close #1
Debug.Print "字写2字符5W行 ", Format(GetTickCount - tTime, "0.0000")'读
Open "c:\L10000S258L.txt" For Binary As #1
ReDim mByte(LOF(1))
Get #1, , mByte
Close #1
DoEvents
tTime = GetTickCount
'字写200字符1W行
Open "c:\L10000S258B.txt" For Binary As #1
Put #1, , mByte
Close #1Debug.Print "字写200字符5W行", Format(GetTickCount - tTime, "0.0000")Debug.Print'这里读的文件大小是相同的,用行输出得到的文本
Debug.Print "这里读的文件大小是相同的,用行输出得到的文本:L10000S258L---9,100,000字节"
DoEvents
tTime = GetTickCount
'行读200字符1W
Open "c:\L10000S258L.txt" For Input As #1
For i = 0 To 49999
Line Input #1, mStr
Next
Close #1Debug.Print "行读200字符5W行", Format(GetTickCount - tTime, "0.0000")
DoEvents
tTime = GetTickCount
'字读200字符1W行
Open "c:\L10000S258L.txt" For Binary As #1
ReDim mByte(LOF(1))
Get #1, , mByte
Close #1
Debug.Print "字读200字符5W行", Format(GetTickCount - tTime, "0.0000")Debug.Print
'这里读的文件大小是相同的,用字节输出得到的文本
Debug.Print "这里读的文件大小是相同的,用字节输出得到的文本:L10000S258B.txt---36,400,004字节"
DoEvents
tTime = GetTickCount
'行读200字符1W
Open "c:\L10000S258B.txt" For Input As #1
For i = 0 To 49999
Line Input #1, mStr
Next
Close #1Debug.Print "行读200字符5W行", Format(GetTickCount - tTime, "0.0000")
DoEvents
tTime = GetTickCount
'字读200字符1W行
Open "c:\L10000S258B.txt" For Binary As #1
ReDim mByte(LOF(1))
Get #1, , mByte
Close #1
Debug.Print "字读200字符5W行", Format(GetTickCount - tTime, "0.0000")
killfile
End SubSub killfile()
On Error Resume Next
Kill "c:\L10000S2L.txt"
Kill "c:\L10000S258L.txt"
Kill "c:\L10000S2B.txt"
Kill "c:\L10000S258B.txt"
End Sub
这里读的文件大小是相同的,用字节输出得到的文本:L10000S258B.txt---36,400,004字节
行读200字符5W行 437.0000
字读200字符5W行 485.0000
我的观点是:字读比行读快。
还是坚持以上观点,原因:
上面的代码里面,在字读的时候REDIM,行读就没有,这一RE可弄没了不少时间
刚才让行读也RE了一下,不过感觉不对头,它们都RE但是RE的不太一样,于是都不RE,得到如下结果:
行写2字符5W行 31.0000
行写200字符5W行 391.0000
字写2字符5W行 31.0000
字写200字符5W行 672.0000这里读的文件大小是相同的,用行输出得到的文本:L10000S258L---9,100,000字节
行读200字符5W行 500.0000
字读200字符5W行 47.0000这里读的文件大小是相同的,用字节输出得到的文本:L10000S258B.txt---36,400,004字节
行读200字符5W行 422.0000
字读200字符5W行 203.0000我还是坚持我的观点:字读快,行读慢,咱就看看只让他们读,别的操作没有的情况下到底如何了
以下是测试代码:测试时在窗体上添加一个名为COMMAND1的按钮
Option Explicit
Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Const mStrI = "12"
Private Const mStrL = "123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890123456890"
Dim mByte() As Long
Dim tTime As Long
Dim mStr(49999) As String
Private Sub Command1_Click()
Dim i As Long
Debug.Print
killfile
'以下写的文件大小不同
tTime = GetTickCount
'行写2字符1W行
Open "c:\L10000S2L.txt" For Output As #1
For i = 0 To 49999
Print #1, mStrI
Next
Close #1
Debug.Print "行写2字符5W行 ", Format(GetTickCount - tTime, "0.0000")
DoEvents
tTime = GetTickCount
'行写200字符1W行
Open "c:\L10000S258L.txt" For Output As #1
For i = 0 To 49999
Print #1, mStrL
Next
Close #1
Debug.Print "行写200字符5W行", Format(GetTickCount - tTime, "0.0000")'读
Open "c:\L10000S2L.txt" For Binary As #1
ReDim mByte(LOF(1))
Get #1, , mByte
Close #1
DoEvents
tTime = GetTickCount
'字写2字符1W行
Open "c:\L10000S2B.txt" For Binary As #1
Put #1, , mByte
Close #1
Debug.Print "字写2字符5W行 ", Format(GetTickCount - tTime, "0.0000")'读
Open "c:\L10000S258L.txt" For Binary As #1
ReDim mByte(LOF(1))
Get #1, , mByte
Close #1
DoEvents
tTime = GetTickCount
'字写200字符1W行
Open "c:\L10000S258B.txt" For Binary As #1
Put #1, , mByte
Close #1Debug.Print "字写200字符5W行", Format(GetTickCount - tTime, "0.0000")Debug.Print'这里读的文件大小是相同的,用行输出得到的文本
Debug.Print "这里读的文件大小是相同的,用行输出得到的文本:L10000S258L---9,100,000字节"
DoEvents
tTime = GetTickCount
'行读200字符1W
Open "c:\L10000S258L.txt" For Input As #1
For i = 0 To 49999
Line Input #1, mStr(i)
Next
Close #1Debug.Print "行读200字符5W行", Format(GetTickCount - tTime, "0.0000")'咱先获取文件字节数REDIM
Open "c:\L10000S258L.txt" For Binary As #1
ReDim mByte(LOF(1))
Close #1
DoEvents
tTime = GetTickCount
'字读200字符1W行Open "c:\L10000S258L.txt" For Binary As #1
Get #1, , mByte
Close #1
Debug.Print "字读200字符5W行", Format(GetTickCount - tTime, "0.0000")Debug.Print
'这里读的文件大小是相同的,用字节输出得到的文本
Debug.Print "这里读的文件大小是相同的,用字节输出得到的文本:L10000S258B.txt---36,400,004字节"
DoEvents
tTime = GetTickCount
'行读200字符1W
Open "c:\L10000S258B.txt" For Input As #1
For i = 0 To 49999
Line Input #1, mStr(i)
Next
Close #1Debug.Print "行读200字符5W行", Format(GetTickCount - tTime, "0.0000")'咱先获取文件字节数REDIM
Open "c:\L10000S258B.txt" For Binary As #1
ReDim mByte(LOF(1))
Close #1
DoEvents
tTime = GetTickCount
'字读200字符1W行
Open "c:\L10000S258B.txt" For Binary As #1
Get #1, , mByte
Close #1
Debug.Print "字读200字符5W行", Format(GetTickCount - tTime, "0.0000")
killfile
End SubSub killfile()
On Error Resume Next
Kill "c:\L10000S2L.txt"
Kill "c:\L10000S258L.txt"
Kill "c:\L10000S2B.txt"
Kill "c:\L10000S258B.txt"
End Sub
1、REDIM占用了大量时间(如第一个代码)
2、在处理行写得到的文件(纯文本文件)时,字节读比行读优势大非常多,8倍
3、在处理字写得到的文件(2进制文件)时,字读比行读优势小一些,2倍
4、在处理2进制文件是,行读速度提高了一些
行读200字符5W行 500.0000
行读200字符5W行 422.0000
但是需要注意的是,2进制文件一般无法用行读处理,我这里的代码是将文本读回来用2进制去写的,其他2进制文件人家可不会给你分行,行读不可行的。
结束;还是坚持我的结论,VB6中字读比行读快
但还是在同一个数量级,差别不大;但split分行耗费了大量的时间,这与CPU的速度有一定关系;基本可以得出结论,如果确实需要得到分行的字符串;
分行读是最好的方法;
我以前认为分行读无法充分利用缓冲区的观点是错误的;如果只是要得到行数另当别论如果只需要分析不需要得到字符串,还有一个方法,比较麻烦
就是二进制读到Byte数组,遍历数组直接分析字符编码
比如数组元素为13,就知道是回车符
也是比较花时间的,
去掉ReDim的话,分行读应该是最快的
而且不需要占额外的CPU资源如果需求是只需要得到每一行的字符串,
应该是首选
答案是会!
除非你禁止使用页面文件。我的禁止了。。
既然说到这里了,就说说我电脑一般配置,得到那些结论。。
双通道DDR400共1GB
CPU SY D325
SATA 硬盘
呵呵,我想让更多的人看到你看一下我在题目里提到.NET区那个帖,
也没有结,呵呵~
当然是文件能全部读到内存不占页面交换文件的情况下。
实际上, 对于任意文件, 可以10M一读, 然后拆分, 记得处理下2次读之间的衔接处。很多情况下, 在循环行读文件慢的地方, 并不是读的操作,
而是字符串连接的操作。
do until eof(1)
line input #1, temp
str = str & temp 或者 text1.text=text1.text & temp
loop慢在了频繁的分配内存上, 尤其是越往后内存数量越大的情况.
对于跟文件读有关的操作, 绝大部分频颈是在 文件i/o上.
所以用任何语言处理效率都相差不大, 当然要注意不要频繁分配内存.
也许实现方法比较笨拙,但也许可以结决大量字符串连接问题
http://blog.csdn.net/viena/archive/2005/10/10/498612.aspx
Option Explicit
Private m_str As String
Private m_lLen As Long
Private m_lPosition As Longsub OpenFile(byval FileName)
一次读入到 m_str
m_lLen = Len(m_str)
m_lPosition = 1
end subFunction ReadLine() As String
Dim i As Long
If m_lPosition > m_lLen Then Exit Function
i = InStr(m_lPosition, m_str, vbCrLf)
If i = 0 Then i = m_lLen + 1
ReadLine = Mid$(m_str, m_lPosition, i - m_lPosition)
m_lPosition = i + 2
End Function如果文件更大,需要对用缓存方式对 StringReader 进行改造:
一、如果文件的行最大字符数容易估计,直接将 Buffer 的大小开成 2 倍以上的行最大字符数,这样 ReadLine 中:只要能找到下个 vbCrLf,就用 Mid 返回结果;否则就将前个 vbCrLf 后免的字符移动到 Buffer 头部,然后读取文件将剩余部分 Buffer 填满。
二、如果行最大字符数无法确定,只能开一个大小比较合理的 Buffer,在 ReadLine 中只要没有找到 vbCrLf,就将整个 Buffer 拼接到返回字符串后面,继续循环读取整个 Buffer。过于频繁地拼接返回字符串会对性能稍有影响。