2015-09-28 103 views
1

我想讀在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。

回答

0

你提供工作的代碼如下:

  1. 它設置一個指向文件的最後一個字符
  2. 它然後讀取該文件向後,直到它找到一個換行符
  3. 它返回所有它讀作爲最後一行。

要修改此爲您的需求,我添加了一個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 
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()over(order by @@ 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 
+0

我更喜歡第二種方法。如何使用ADO獲取文件?可以進一步解釋? – lakesh

+0

剛剛更新了我的答案,解釋爲什麼ADO不值得深入研究。但是,如果你仍然想要沿着這條路線,那麼簡單地從以下任何一個複製:http://stackoverflow.com/questions/16898046/copying-text-from-txt-file-in-excel-using-ado-ignores-第一行http://stackoverflow.com/questions/22947425/using-ado-to-query-text-files-terrible-performance步驟是一樣的:(1)'從SELECT * MyTextFile.txt'然後保存總是兩個字符串並循環到'recordset'的末尾。一旦你在最後你可以輸出最後兩行。 – Ralph

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)

+0

該文件非常大。所以它給我的內存不足 – lakesh

+0

在這種情況下,你可以通過提取最後一個例如緩衝區來創建一個緩衝區。 10000個字符作爲字符串並將其用作GetSecondLastLine中的sContent –

相關問題