Ниже приведена часть кода, который у меня есть, который попросит пользователя выбрать нужный файл .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
Пожалуйста, попробуйте следующий фрагмент кода. Он позволял вам выбрать папку для обработки, затем перебирать все существующие текстовые файлы, помещать их содержимое в массив, помещать содержимое в вычисленную последнюю строку и, наконец, применять 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
Он использует ту же функцию для определения папки, подлежащей обработке.
Решение 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