Excel VBA, чтобы выбрать папку и загрузить файлы TXT внутри

Ниже приведена часть кода, который у меня есть, который попросит пользователя выбрать нужный файл .txt, и он загрузится в Excel. Можно ли разрешить пользователю выбрать папку, в которой находится несколько файлов .txt, и он загрузится? в эксель? Например, есть папка с именем log, внутри нее есть log1.txt, log2.txt и т. д. Пользователь выберет папку с именем log, и все текстовые файлы внутри будут записаны на имеющийся у меня лист Excel. Или есть метод, с помощью которого я могу зациклить имеющийся у меня макрос в зависимости от количества текстовых файлов, которые у меня есть в папке, чтобы он записывал каждый текстовый файл соответственно на листе Excel.

    textFileLocation = Application.GetOpenFilename()
    textDelimiter = ","
    textFileNum = FreeFile
    Open textFileLocation For Input As textFileNum
    textData = Input(LOF(textFileNum), textFileNum)
    Close textFileNum
    tArray() = Split(textData, vbLf)
    For rowNum = LBound(tArray) To UBound(tArray) - 1
        If Len(Trim(tArray(rowNum))) <> 0 Then
            sArray = Split(tArray(rowNum), textDelimiter)
            For colNum = LBound(sArray) To UBound(sArray)
                ActiveSheet.Cells(rowNum + 1, colNum + 1) = sArray(colNum)
            Next colNum
        End If
    Next rowNum

    Columns("A:A").Select
    Selection.TextToColumns Destination:=Range("A1"), DataType:=xlFixedWidth, _
    FieldInfo:=Array(Array(0, 1), Array(43, 1), Array(70, 1)), TrailingMinusNumbers _
    :=True

Что вы подразумеваете под «чтобы он записывал каждый текстовый файл соответственно на листе Excel»? Будете ли вы записывать текст каждого файла под предыдущим или каждый файл на новом листе? Если на том же листе, есть ли в скопированном тексте заголовки столбцов? Если да, то как действовать? Должен ли код копировать заголовок только для первого файла или для всех? В конце концов, чтобы знать, где они начинаются и заканчиваются...

FaneDuru 02.09.2024 10:22

@FaneDuru будет записывать текст каждого файла ниже предыдущего. Текущий код, который у меня есть, заключается в том, что пользователь выберет файл и вставит данные из текстового файла в лист, затем отфильтрует и скопирует и вставит нужные мне данные на другой лист. Но сейчас у меня есть несколько текстовых файлов, поэтому я хочу, чтобы он мог просмотреть весь текстовый файл, который у меня есть в папке, и записать его в лист Excel, спасибо.

user23357972 02.09.2024 10:28

Дайте нам образец содержимого текстовых файлов, чтобы можно было настроить различные решения.

Haluk 02.09.2024 10:38

@Haluk, я вижу, что не включил в основном потому, что боялся, что это будет слишком долго, обычно содержимое текстовых файлов будет разделено на 3 столбца: имя атрибута (AN), данные атрибута (AD) и единицы измерения (U). После этого он скопирует и вставит данные атрибута на другой лист, где они будут соответствовать имени атрибута. Пример: температура устройства (AN), 280 (AD), кельвины (U). Эта информация в текстовом файле будет записана в Лист1, затем она будет соответствовать (AN) на листе2 и вставлена ​​в нее. Если на листе2 нет (AN), он не будет записывать (AD). Это относится ко всем текстовым файлам, которые есть в папке.

user23357972 02.09.2024 10:56

Если текстовые файлы имеют один и тот же формат каждый раз, у меня будет путь к папке в ячейке. Событие двойного щелчка, чтобы открыть диалоговое окно папки и изменить его. Затем используйте PowerQuery для импорта всех текстовых файлов в этой папке.

Darren Bartrup-Cook 02.09.2024 11:07

Пожалуйста, не расширяйте свой вопрос здесь, в комментариях. Вместо этого отредактируйте свой вопрос.

Tom Brunberg 02.09.2024 11:14

Как будет работать PowerQuery? В настоящее время мой код работает, выбирая файл log1.txt и вставляя его в Лист1, а затем вставляя данные в Лист2. Затем я снова запущу код и выберу файл log2.txt, он вставит его в Лист1 и вставит данные в Лист2. Итак, я хочу, чтобы он автоматически запускался из файла log1.txt в файл log100.txt и делал одно и то же для каждого файла log.txt. Формат каждого текстового файла одинаков.

user23357972 02.09.2024 11:15

Я вижу в вашем коде textDelimiter = "," Что это значит? Не разделитель столбцов? я вижу, что ты не используешь его в TextToColumns...

FaneDuru 02.09.2024 11:17
Преобразование HTML-таблицы в профессиональный документ Excel
Преобразование HTML-таблицы в профессиональный документ Excel
Это самый простой способ создания Excel из HTML-таблицы.
Импорт excel в laravel в базу данных
Импорт excel в laravel в базу данных
Здравствуйте, дорогой читатель, в этой статье я расскажу практическим и быстрым способом, как импортировать файл Excel в вашу базу данных с помощью...
0
8
56
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Пожалуйста, попробуйте следующий фрагмент кода. Он позволял вам выбрать папку для обработки, затем перебирать все существующие текстовые файлы, помещать их содержимое в массив, помещать содержимое в вычисленную последнюю строку и, наконец, применять TextToColumns. Он считает запятую разделителем столбцов:

Sub ProcessFilesFromChosenFolder()
  Dim textFileLocation As String, textDelimiter As String, fileName As String, arrTxt
  Dim ws As Worksheet, lastR As Long
  
  Set ws = Application.ActiveSheet 'use here the sheet you need
  textFileLocation = GetFolderName("This PC") 'if you need it to be open in a specific folder, place here its path
  
  fileName = Dir(textFileLocation & "\*.txt") 'first text file  name
  
  If fileName <> "" Then
    Do While fileName <> ""    'loop since there still are not processed text files
        'place the content of the text file in an array (split by VbCrLf):
        arrTxt = Split(CreateObject("Scripting.FileSystemObject").OpenTextFile(textFileLocation & "\" & fileName, 1).ReadAll, vbCrLf)
        lastR = ws.Range("A" & ws.rows.count).End(xlUp).row 'the row where to paste the array content

        'drop the transposed array content:
        ws.Range("A" & IIf(lastR = 1, lastR, lastR + 1)).Resize(UBound(arrTxt) + 1, 1).Value = Application.Transpose(arrTxt)
        
        fileName = Dir 'find the next text file
    Loop
  End If
  'apply TextToColumns to whole returned data:
  ws.Columns(1).TextToColumns Destination:=ws.Range("A1"), DataType:=xlDelimited, ConsecutiveDelimiter:=False, Comma:=True, _
             FieldInfo:=Array(Array(0, 1), Array(43, 1), Array(70, 1)), TrailingMinusNumbers:=True
End Sub

Function GetFolderName(InitPath As String) As String
    With Application.FileDialog(msoFileDialogFolderPicker)

        If InitPath <> "" Then
            If Right$(InitPath, 1) <> "\" Then
                InitPath = InitPath & "\"
            End If
            .InitialFileName = InitPath
        Else
            .InitialFileName = ""   'it starts at This PC...
        End If
        
        If .Show() = True Then
            If .SelectedItems.count > 0 Then
                GetFolderName = .SelectedItems(1)
            End If
        End If

    End With
End Function

Отредактировано:

В следующей версии не требуется TextToColumns, она разбивает каждую начальную строку массива по разделителю (запятой) и загружает третий финальный массив, чтобы удалить его содержимое после каждого обработанного текстового файла:

Sub ProcessFilesFromChosenFolderBis()
  Dim textFileLocation As String, fileName As String, ws As Worksheet, lastR As Long
  Dim arrTxt, arrLine, ColsNo As Long, arrFin, i As Long, j As Long
  Const textDelimiter As String = ","
  
  Set ws = Application.ActiveSheet 'use here the sheet you need
  textFileLocation = GetFolderName("This PC") 'if you need it to be open in a specific folder, place here its path
  
  fileName = Dir(textFileLocation & "\*.txt") 'first text file  name
  
  If fileName <> "" Then
    Do While fileName <> ""    'loop since there still are not processed text files
        'place the content of the text file in an array (split by VbCrLf):
        arrTxt = Split(CreateObject("Scripting.FileSystemObject").OpenTextFile(textFileLocation & "\" & fileName, 1).ReadAll, vbCrLf)
        ColsNo = UBound(Split(arrTxt(0), textDelimiter)) + 1 ' determine number of columns
        ReDim arrFin(1 To UBound(arrTxt) + 1, 1 To ColsNo)   'redim the aray to keep the processed data

        For i = 0 To UBound(arrTxt)
            arrLine = Split(arrTxt(i), textDelimiter) 'place each row/line in an array
            For j = 0 To UBound(arrLine): arrFin(i + 1, j + 1) = arrLine(j): Next j 'load final array
        Next i
        
        lastR = ws.Range("A" & ws.rows.count).End(xlUp).row 'the row where to paste the array content
        'drop the processed final array content:
        ws.Range("A" & IIf(lastR = 1, lastR, lastR + 1)).Resize(UBound(arrFin), UBound(arrFin, 2)).Value = arrFin
        
        fileName = Dir 'find the next text file
    Loop
  End If
  MsgBox "Ready..."
End Sub

Он использует ту же функцию для определения папки, подлежащей обработке.

Привет, спасибо за помощь, все работает так, как я и предполагал, только небольшая проблема. Когда я запускаю код, он не отображает имеющийся у меня текстовый файл, он перейдет в мое местоположение, но я не могу его увидеть, но когда я нажимаю «Выполнить», он все равно будет проходить через весь мой текстовый файл, поэтому он работает, но есть какие-то проблемы со зрением?

user23357972 03.09.2024 04:52

Решение PowerQuery.

В Excel выберите «Данные» > «Получить данные» > «Из файла» > «Из папки»
.

В открывшемся диалоговом окне выберите папку, содержащую ваши текстовые файлы, и нажмите Transform Data.
.

Нажмите две стрелки вниз в столбце Content, чтобы развернуть данные.

Нажмите OK на следующем экране, чтобы импортировать данные.

Примените дальнейшие вычисления, чтобы получить нужные вам данные, и нажмите кнопку Close & Load, чтобы импортировать итоговую таблицу в Excel.

В PQ кнопка «Расширенный редактор» должна предоставить вам сценарий, подобный приведенному ниже. У вас также будет несколько вспомогательных запросов, созданных для вас PQ.

let
    Source = Folder.Files("H:\Test\Text Files"),
    #"Filtered Hidden Files1" = Table.SelectRows(Source, each [Attributes]?[Hidden]? <> true),
    #"Invoke Custom Function1" = Table.AddColumn(#"Filtered Hidden Files1", "Transform File", each #"Transform File"([Content])),
    #"Renamed Columns1" = Table.RenameColumns(#"Invoke Custom Function1", {"Name", "Source.Name"}),
    #"Removed Other Columns1" = Table.SelectColumns(#"Renamed Columns1", {"Source.Name", "Transform File"}),
    #"Expanded Table Column1" = Table.ExpandTableColumn(#"Removed Other Columns1", "Transform File", Table.ColumnNames(#"Transform File"(#"Sample File"))),
    #"Changed Type" = Table.TransformColumnTypes(#"Expanded Table Column1",{{"Source.Name", type text}, {"Attribute Name", type text}, {"Attribute Data", type text}, {"Units", Int64.Type}})
in
    #"Changed Type"

Теперь нам просто нужно добавить функцию, которая позволит нам изменить путь к файлу в первой строке запроса.

Создайте новый пустой запрос, используя Данные > Получить данные > Из других источников > Пустой запрос.
Добавьте этот код в запрос — он считывает значение из именованного диапазона. Я назвал этот запрос fGetNamedRange.

let GetNamedRange=(NamedRange) => 
    let
        name = Excel.CurrentWorkbook(){[Name=NamedRange]}[Content],
        value = name{0}[Column1]
    in
        value
in GetNamedRange  

Обновите первую строку исходного запроса. Я присвоил ячейке именованный диапазон MyFolderPath:

//Source = Folder.Files("H:\Test\Text Files"),
Source = Folder.Files(Text.From(fGetNamedRange("MyFolderPath"))),  

Последний шаг — добавить код VBA, который позволит вам обновить папку.

В обычный модуль добавьте этот код:

Public Function GetFolderName() As String

    Dim FD As FileDialog
    Set FD = Application.FileDialog(msoFileDialogFolderPicker)
    
    With FD
        .Title = "Select a Folder"
        .InitialFileName = ThisWorkbook.Path & Application.PathSeparator
        .AllowMultiSelect = False
        
        If .Show = -1 Then
            GetFolderName = .SelectedItems(1)
        End If
    End With
    
    Set FD = Nothing

End Function

В коде листа, где хранится путь к вашей папке:

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
    If Target.Address = "$B$2" Then
        Cancel = True
        Target.Value2 = GetFolderName() & Application.PathSeparator
        
        If MsgBox("Refresh query?", vbYesNo + vbQuestion) = vbYes Then
            ThisWorkbook.Connections("Query - Text Files").Refresh 'NB - query is called "Text Files", but must add "Query - " in front of it.
        End If
    End If
End Sub

Другие вопросы по теме