You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

批量读取数千CSV时FreeFile触发Error 67的解决及替代方案

背景

需要读取多文件夹下的数千个CSV文件,仅提取每个文件的最后一行数据做分析,用FreeFile实现(PowerQuery不适用此场景)。曾临时把文件句柄扩展到512,但这不是根本解决办法。

问题

就算关闭文件,内存也没正确释放,循环处理一定数量的文件后会触发Error 67(文件过多)。尝试循环直到FreeFile返回1(还加了Sleep延迟)也没用,FreeFile最终会涨到2。

现有代码

编写了Return_VarInCSVLine函数来获取指定行数据:

Function Return_VarInCSVLine(ByRef NumLineToReturnTo As Long, ByRef TxtFilePathCSV As String, Optional ByRef IsLastLine As Boolean) As Variant
If NumLineToReturnTo = 0 Then NumLineToReturnTo = 1
'NumLineToReturnTo has to be at least 1 even if LastLine is set to true so no error is arised from IIF
Dim NumFileInMemory As Long
Dim ArrVarTxtLines() As Variant
Dim CounterArrTxtLines As Long
Dim TxtInLine As String
    NumFileInMemory = FreeFile: CounterArrTxtLines = 1
    Open TxtFilePathCSV For Input As #NumFileInMemory: DoEvents
    Do While Not EOF(NumFileInMemory)
    Line Input #NumFileInMemory, TxtInLine
    ReDim Preserve ArrVarTxtLines(1 To CounterArrTxtLines)
    ArrVarTxtLines(CounterArrTxtLines) = TxtInLine
    CounterArrTxtLines = CounterArrTxtLines + 1
    Loop
LoopUntilClosed:
    Close #NumFileInMemory: Sleep (10): DoEvents
    NumFileInMemory = FreeFile
    If NumFileInMemory > 1 Then GoTo LoopUntilClosed
    Return_VarInCSVLine = IIf(IsLastLine = True, ArrVarTxtLines(UBound(ArrVarTxtLines)), ArrVarTxtLines(NumLineToReturnTo))
End Function
解决方案与替代方案

错误修复:优化现有代码

当前代码的核心问题是读取并存储整个文件内容,既浪费内存,又拉长了文件句柄的占用时间;另外LoopUntilClosed循环完全没必要——FreeFile返回大于1只是系统缓存了句柄编号,不是文件没关闭,强行循环反而拖慢程序。

针对「仅需最后一行」的核心需求,修改代码如下,只保留最后一行数据,大幅减少内存占用和句柄使用时长:

Function Return_VarInCSVLine(ByRef NumLineToReturnTo As Long, ByRef TxtFilePathCSV As String, Optional ByRef IsLastLine As Boolean) As Variant
    If NumLineToReturnTo = 0 Then NumLineToReturnTo = 1
    Dim NumFileInMemory As Long
    Dim TxtInLine As String
    Dim lastLine As String
    Dim lineCount As Long
    
    NumFileInMemory = FreeFile
    Open TxtFilePathCSV For Input As #NumFileInMemory
    Do While Not EOF(NumFileInMemory)
        Line Input #NumFileInMemory, TxtInLine
        lineCount = lineCount + 1
        ' 只保留最后一行,不存储所有行
        lastLine = TxtInLine
    Loop
    Close #NumFileInMemory
    
    If IsLastLine Then
        Return_VarInCSVLine = lastLine
    Else
        ' 若需指定行,重新读取到目标行即可
        Open TxtFilePathCSV For Input As #NumFileInMemory
        lineCount = 0
        Do While Not EOF(NumFileInMemory) And lineCount < NumLineToReturnTo
            Line Input #NumFileInMemory, TxtInLine
            lineCount = lineCount + 1
        Loop
        Close #NumFileInMemory
        Return_VarInCSVLine = TxtInLine
    End If
End Function

替代方案

1. 使用FileSystemObject(FSO)读取最后一行

语法更直观,性能与FreeFile接近:

Function GetCSVLastLine(ByVal filePath As String) As String
    Dim fso As Object
    Dim txtStream As Object
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set txtStream = fso.OpenTextFile(filePath, 1) ' 1=只读模式
    
    Dim lastLine As String
    Do While Not txtStream.AtEndOfStream
        lastLine = txtStream.ReadLine
    Loop
    
    txtStream.Close
    Set txtStream = Nothing
    Set fso = Nothing
    GetCSVLastLine = lastLine
End Function

2. 直接读取文件尾部(最高效)

无需读取整个文件,仅从文件末尾往前查找换行符,速度极快,适合大文件批量处理:

Function GetCSVLastLineFast(ByVal filePath As String) As String
    Dim fileNum As Long
    Dim fileSize As Long
    Dim buffer As String
    Dim pos As Long
    
    fileNum = FreeFile
    Open filePath For Binary As #fileNum
    fileSize = LOF(fileNum)
    
    ' 读取文件末尾最多1024字节(足够覆盖一行CSV内容)
    buffer = Space$(Min(1024, fileSize))
    Get #fileNum, fileSize - Len(buffer) + 1, buffer
    
    ' 定位最后一个换行符
    pos = InStrRev(buffer, vbCrLf)
    If pos > 0 Then
        GetCSVLastLineFast = Mid(buffer, pos + 2)
    Else
        ' 文件只有一行,直接读取全部内容
        buffer = Space$(fileSize)
        Get #fileNum, 1, buffer
        GetCSVLastLineFast = buffer
    End If
    
    Close #fileNum
End Function

Function Min(a As Long, b As Long) As Long
    If a < b Then Min = a Else Min = b
End Function

3. 批量处理补充优化

每次处理完文件后,可添加以下代码强制释放资源(作为补充优化):

DoEvents
CollectGarbage

内容的提问来源于stack exchange,提问作者Sgdva

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 13:06:24