2015-09-28 5 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. Затем он считывает файл в обратном направлении до тех пор, пока не найдет LineBreak
  3. Он возвращает все это прочитано как последняя строка.

Чтобы изменить это для ваших нужд, я добавил Boolean secondRun, который позволяет запускать код шаг 2 снова, таким образом, запись 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- first-row http://stackoverflow.com/questions/22947425/using-ado-to-query-text-files-terrible-performance. Шаги те же: (1) 'SELECT * from 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 

При необходимости, вы можете изменить строку разделитель (например vbCR из vbLF)

+0

Файл очень большой. поэтому он не дает мне памяти – lakesh

+0

В этом случае вы можете сделать буфер сначала, извлекая последний, например. 10000 символов в качестве строки и использовать это как sContent в GetSecondLastLine –

Смежные вопросы