如何阅读文本文件中的倒数第二行

时间:2015-09-28 09:07:07

标签: excel vba excel-vba

我想在VBA中阅读一个大文件并在线查看此代码:

Dim MyChar As String, Pointer As Long, LastLine As String
Open "MyTextFile.Txt" For Binary As #1
Pointer = LOF(1) - 2
MyChar = Chr$(32)
Do
    Get #1, Pointer, MyChar
    If MyChar = vbCr Or MyChar = vbLf Then
        Exit Do
    Else: Pointer = Pointer - 1
        LastLine = MyChar & LastLine
    End If
Loop
MsgBox "Last Line is " & LastLine

如何更改此代码以获取倒数第二行?需要一些帮助。

想到这个:

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile _
    "MyTextFile.Txt", 1)
objTextFile.ReadAll
MsgBox objTextFile.Line

但我无法进入第2行。

3 个答案:

答案 0 :(得分:1)

取决于你的方法。但是如果文件真的那么大,那么你可能不希望Excel加载整个文件。因此,您可能会打开文件并逐行读取,而不知道文件有多大以及文件有多少行。在这种情况下,最简单的方法是在两个单独的字符串变量中一次存储两行。一旦你到达最后一行,你可以退出你的循环 - 如上面的代码所示 - 并且不仅输出最后一行(如代码中已经完成的那样),还输出该文件中第二行的内容。

Public Sub GetSecondLastRow()
Dim strSecondLastLine As String
Dim strFileToImport As String
Dim strLastLine As String
Dim intPointer As Integer
Dim lngCounter As Long

strFileToImport = ThisWorkbook.Path & IIf(InStr(1, ThisWorkbook.Path, "\") > 0, "\", "/") & "MyTextFile.txt"

intPointer = FreeFile()
Open strFileToImport For Input Access Read Lock Read As #intPointer

lngCounter = 0
Do Until EOF(lngCounter)
    strSecondLastLine = strLastLine
    Line Input #intPointer, strLastLine
    lngCounter = lngCounter + 1
Loop

Close intPointer

Debug.Print "Content of the second last row:"
Debug.Print "---------------------------------------"
Debug.Print strSecondLastLine
Debug.Print "---------------------------------------"
Debug.Print "Content of the last row:"
Debug.Print "---------------------------------------"
Debug.Print strLastLine

End Sub

另一种方法是先查询文件的行数,然后使用ADO获取该文件中的倒数第二条记录。但我怀疑那会更快。 ADO的问题在于你得到一个包含整个文本文件的巨大recordset背面。这是因为您在SELECT * from MyTextFile.txt条款中没有任何限制。因此,整个文本文件进入内存之前您可以对其执行任何操作。然后 - 当然 - 您可以检查RecordCount并再次使用光标快速返回所有记录,直到您到达倒数第二行。不幸的是,ADO不支持

  

row_number()结束(按@@ ROWCOUNT排序)。

否则,您可以先使用select count(1) from MyTextFile.txt获取行计数,然后再使用适用的行。

所以,无论如何,我几乎可以肯定(没有经过测试)ADO的性能低于标准,如果文本文件和你说的一样大,那么第一个解决方案就是这样。如果您仍然喜欢ADO,那么这就是代码(基于以下SO问题/答案:Copying text from .txt file in Excel using ADO ignores first row)。

 Sub ImportTextFile()

'Imports text file into Excel workbook using ADO.
'If the number of records exceeds 65536 then it splits it over more than one sheet.
Dim strFilePath As String, strFilename As String, strFullPath As String
Dim lngCounter As Long
Dim oConn As ADODB.Connection
Dim oRS As ADODB.Recordset
Dim oFSObj As Object

'Get a text file name
strFullPath = Application.GetOpenFilename("Text Files (*.txt),*.txt", , "Please select text file...")

If strFullPath = "False" Then Exit Sub  'User pressed Cancel on the open file dialog

'This gives us a full path name e.g. C:\temp\folder\file.txt
'We need to split this into path and file name
Set oFSObj = CreateObject("SCRIPTING.FILESYSTEMOBJECT")

strFilePath = oFSObj.GetFile(strFullPath).ParentFolder.Path
strFilename = oFSObj.GetFile(strFullPath).Name

'Open an ADO connection to the folder specified
Set oConn = New ADODB.Connection
oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
               "Data Source=" & strFilePath & ";" & _
               "Extended Properties=""text;HDR=No;FMT=Delimited"""

Set oRS = New ADODB.Recordset
'Now actually open the text file and import into Excel
oRS.Open "SELECT count(1) FROM [" & strFilename & "]", oConn, 3, 1, 1

Range("A1").CopyFromRecordset oRS

Set oRS = New ADODB.Recordset
'Now actually open the text file and import into Excel
oRS.Open "SELECT * FROM [" & strFilename & "]", oConn, 3, 1, 1

While Not oRS.EOF And Not oRS.BOF
    If oRS.AbsolutePosition = Range("A1").Value2 Then
        Range("A2").Value = oRS.Fields(0).Value
    End If
    oRS.MoveNext
Wend

oRS.Close
oConn.Close

End Sub

答案 1 :(得分:0)

您提供的代码如下:

  1. 设置指向文件最后一个字符的指针
  2. 然后它会向后读取该文件,直到找到换行符
  3. 它返回它作为最后一行读取的所有内容。
  4. 为了根据您的需要进行修改,我添加了一个Boolean secondRun,让代码再次运行第2步,从而记录第二行:

    Dim MyChar As String, Pointer As Long, LastLine As String
    Open "MyTextFile.Txt" For Binary As #1
    Pointer = LOF(1) - 2
    MyChar = Chr$(32)
    Dim secondRun As Boolean
    Do
        ' Read character at position "Pointer" into variable "MyChar"
        Get #1, Pointer, MyChar
        If MyChar = vbCr Or MyChar = vbLf Then  ' Linebreak = line read completely
            If Not secondRun Then
                ' Run again if we've read only one line so far
                secondRun = True
                LastLine = ""
                Pointer = Pointer - 2
            Else
                Exit Do
            End If
        Else: Pointer = Pointer - 1
            ' Add character to result String
            LastLine = MyChar & LastLine
        End If
    Loop
    MsgBox " 2nd last line is " & LastLine
    

答案 2 :(得分:0)

你可以试试这个:

Public Function GetSecondLastLine(sFileName As String, Optional sLineDelimiter As String = vbCrLf) As String

    Dim sContent    As String
    Dim aLines()    As String

    sContent = TextFromFile(sFileName)

    aLines = Split(sContent, sLineDelimiter)

    GetSecondLastLine = aLines(UBound(aLines) - 1)

End Function

Public Function TextFromFile(sFileName As String) As String

    Dim lFile As Long

    lFile = FreeFile
    Open sFileName For Input As #lFile
    TextFromFile = Input$(LOF(lFile), lFile)
    Close #lFile

End Function

如有必要,您可以更改行分隔符(例如vbLF的vbCR)