【问题标题】:VBA – print file name in each row until the file closesVBA – 在每一行中打印文件名,直到文件关闭
【发布时间】:2015-06-10 12:15:30
【问题描述】:

我有一个工作宏,它遍历文件夹以打开文件并从名称“HOLDER”和“CUTTING TOOL”列中获取重要信息,并将所有信息打印到一个 Excel 文档 masterfile。

它目前看起来像图片 1。我希望它在每行的第一列中打印文件名,直到文件关闭,这样对于第 2 列和第 3 列中的每个条目,第一列中也有文件名条目,如图 2 所示。

我想对第 4 列应用相同的内容,在每一行中打印名称。我不知道这些信息是否有帮助,因为获取第 1 列和第 4 列的信息是在第 (5) 节的同一代码块中编写的。

有人可以帮我弄清楚如何解决这个问题吗?我一直在尝试在代码的那部分 (5) 中实现某种“i++”……但没有成功。感谢您的任何建议!

完整代码 第 (5) 节处理主文件第 1 列和第 4 列中文件的命名。

Option Explicit

Sub LoopThroughDirectory()

    Const ROW_HEADER As Long = 10

    Dim objFSO As Object
    Dim objFolder As Object
    Dim objFile As Object
    Dim MyFolder As String
    Dim StartSht As Worksheet, ws As Worksheet
    Dim WB As Workbook
    Dim i As Integer
    Dim LastRow As Integer, erow As Integer
    Dim Height As Integer
    Dim RowLast As Long
    Dim f As String
    Dim dict As Object
    Dim hc As Range, hc1 As Range, hc2 As Range, hc3 As Range, d As Range

    Set StartSht = Workbooks("masterfile.xlsm").Sheets("Sheet1")

    'turn screen updating off - makes program faster
    Application.ScreenUpdating = False

    'location of the folder in which the desired TDS files are
    MyFolder = "C:\Users\trembos\Documents\TDS\progress\"

    'find the headers on the sheet
    Set hc1 = HeaderCell(StartSht.Range("B1"), "HOLDER")
    Set hc2 = HeaderCell(StartSht.Range("C1"), "CUTTING TOOL")

    'create an instance of the FileSystemObject
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    'get the folder object
    Set objFolder = objFSO.GetFolder(MyFolder)
    i = 2


    'loop through directory file and print names
'(1)
    For Each objFile In objFolder.Files
        If LCase(Right(objFile.Name, 3)) = "xls" Or LCase(Left(Right(objFile.Name, 4), 3)) = "xls" Then
'(2)

            'Open folder and file name, do not update links
            Set WB = Workbooks.Open(fileName:=MyFolder & objFile.Name, UpdateLinks:=0)
            Set ws = WB.ActiveSheet
'(3)
                'find CUTTING TOOL on the source sheet
                Set hc = HeaderCell(ws.Cells(ROW_HEADER, 1), "CUTTING TOOL")
                If Not hc Is Nothing Then

                    Set dict = GetValues(hc.Offset(1, 0), "SplitMe")
                    If dict.count > 0 Then
                        Set d = StartSht.Cells(Rows.count, hc2.Column).End(xlUp).Offset(1, 0)
                        'add the values to the master list, column 3
                        d.Resize(dict.count, 1).Value = Application.Transpose(dict.items)
                    End If
                Else
                    'header not found on source worksheet
                End If
'(4)
                'find HOLDER on the source sheet
                Set hc3 = HeaderCell(ws.Cells(ROW_HEADER, 1), "HOLDER")
                If Not hc3 Is Nothing Then

                    Set dict = GetValues(hc3.Offset(1, 0))
                    If dict.count > 0 Then
                        Set d = StartSht.Cells(Rows.count, hc1.Column).End(xlUp).Offset(1, 0)
                        'add the values to the master list, column 2
                        d.Resize(dict.count, 1).Value = Application.Transpose(dict.items)
                    End If
                Else
                    'header not found on source worksheet
                End If
'(5)
            With WB
               'print TDS information
                For Each ws In .Worksheets
                        'print the file name to Column 1
                        StartSht.Cells(i, 1) = objFile.Name
                        'print TDS name from J1 cell to Column 4
                        With ws
                            .Range("J1").Copy StartSht.Cells(i, 4)
                        End With
                        i = GetLastRowInSheet(StartSht) + 1
                'move to next file
                Next ws
'(6)
                'close, do not save any changes to the opened files
                .Close SaveChanges:=False
            End With
        End If
    'move to next file
    Next objFile
    'turn screen updating back on
    Application.ScreenUpdating = True
    ActiveWindow.ScrollRow = 1
'(7)
End Sub

'(8)
'get all unique column values starting at cell c
Function GetValues(ch As Range, Optional vSplit As Variant) As Object
    Dim dict As Object, rng As Range, c As Range, v
    Dim spl As Variant
    Set dict = CreateObject("scripting.dictionary")
    For Each c In ch.Parent.Range(ch, ch.Parent.Cells(Rows.count, ch.Column).End(xlUp)).Cells
        v = Trim(c.Value)
        If Len(v) > 0 And Not dict.exists(v) Then

            If Not IsMissing(vSplit) Then
            spl = Split(v, ";")

            v = spl(0)
            End If

            If Not IsMissing(vSplit) Then
            spl = Split(v, ",")

            v = spl(0)
            End If


            dict.Add c.Address, v
        End If
    Next c
    Set GetValues = dict
End Function

'(9)
'find a header on a row: returns Nothing if not found
Function HeaderCell(rng As Range, sHeader As String) As Range
    Dim rv As Range, c As Range
    For Each c In rng.Parent.Range(rng, rng.Parent.Cells(rng.Row, Columns.count).End(xlToLeft)).Cells
        If Trim(c.Value) = sHeader Then
            Set rv = c
            Exit For
        End If
    Next c
    Set HeaderCell = rv
End Function

'(10)
Function GetLastRowInColumn(theWorksheet As Worksheet, col As String)
    With theWorksheet
        GetLastRowInColumn = .Range(col & .Rows.count).End(xlUp).Row
    End With
End Function

'(11)
Function GetLastRowInSheet(theWorksheet As Worksheet)
Dim ret
    With theWorksheet
        If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
            ret = .Cells.Find(What:="*", _
                          After:=.Range("A1"), _
                          Lookat:=xlPart, _
                          LookIn:=xlFormulas, _
                          SearchOrder:=xlByRows, _
                          SearchDirection:=xlPrevious, _
                          MatchCase:=False).Row
        Else
            ret = 1
        End If
    End With
    GetLastRowInSheet = ret
End Function

【问题讨论】:

    标签: vba excel filenames


    【解决方案1】:

    由于您已经有办法一次找出最后使用的行,因此您非常接近解决方案。您要做的是将objFile.Name 不仅写入StartSht.Cells(i, 1),而且写入StartSht.Range(StartSht.Cells(i, 1), StartSht.Cells(GetLastRowInColumn(StartSht, 3), 1))

    分解:

    StartSht.Range() 寻址工作表StartSht 中的一个矩形区域。您可以通过提供角来指定此区域:StartSht.Cells(i, 1) 是您已经知道的上角,GetLastRowInColumn(StartSht, 3) 为您获取刚刚在第 (3) 和 (4) 节中写入的数据的最后一行。因此,StartSht.Cells(GetLastRowInColumn(StartSht, 3), 1) 最终确定了您的区域并写入了objFile.Name 的值。

    然后你可以用你的复制命令做同样的事情。

    【讨论】:

    • 好的。这很有意义。谢谢你解释你的意思。我将在哪里实施?因为为了使用 GetLastRowInColumn.. 它必须从第 2 列或第 3 列获取最后一行,然后将其打印到 1..因为 1 仅在第一个单元格中包含信息。 @Verzweifler
    • 哦,等一下,我明白你的代码行现在是什么意思,但仍然不确定在哪里实现它。我试图在第 5 节中替换 StartSht.Cells(i, 1) = objFile.Name,但这导致第 (10) 节函数中出现错误,指出 GetLastRowInColumn 行超出范围
    • 我尝试创建另一个相同的函数,但用 StartSht 替换了 Worksheet ...但 GetLastRowInColumn 仍然超出范围,我无法弄清楚@Verzweifler
    • @Taylor:对不起,我没有看到函数GetLastRowInColumn 需要一个字符串作为列参数!在这种情况下,将GetLastRowInColumn(StartSht, 3) 替换为GetLastRowInColumn(StartSht, "C") 或者,您可以使用GetLastRowInSheet 函数并且只传递StartSht 作为参数。
    • 这有两个部分;我将从GetLastRowInSheet 开始:该函数利用 Cells.find() 函数查找工作表的最后一个单元格,然后获取其中的.row。就个人而言,我发现GetLastRowInColumn-function 更直观。请确保按原样使用StartSht.Range(StartSht.Cells(i, 1), StartSht.Cells(GetLastRowInColumn(StartSht, 3), 1)) 行,以避免寻址两个单独的单元格 - 两个内部单元格地址周围的Range()-运算符很重要!
    猜你喜欢
    • 1970-01-01
    • 2014-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-12
    • 1970-01-01
    • 2016-06-05
    • 1970-01-01
    相关资源
    最近更新 更多