代码无法读取循环读取的多个文件以及要导入的特殊行

时间:2014-01-10 22:47:23

标签: excel excel-vba vba

我非常渴望得到你的帮助,以便在今天结束前修复这些代码,因为我的老板希望它能够完成。我无法弄清楚如何设置循环来读取.txt中的多个文件,然后将特殊行导入excel !!请帮帮我。

Sub ImportFile()
    Dim J As Long, K As Long
    Close #1
    Open "C:\TestFolder\TestFile.txt" For Input As #1
    For Each f In A$
        J = 1
        K = 0
        Do While Not EOF(1)
            K = K + 1
            Line Input #1, TextLine

            If K = 22 Then
                ws.Range("a1").Cells(J, 2) = Mid(TextLine, 20, 16)
            End If

            If K > 69 And K < 77 Then
                ws.Range("a2").Cells(J, 2) = Mid(TextLine, 1, 9)
                J = J + 1
            End If
        Loop
    Next

2 个答案:

答案 0 :(得分:3)

你说:我已经查看了所有问题并注意到大部分问题都是通过创建脚本得到答案的?我对stackoverflow的目的是为了让我们拥有这个网站?如果我们感到陷阱或麻烦,请提供脚本吗?

这个答案有很多,其中一些在一读时没有意义。我相信经过一番研究后,eveything会有意义。您可能需要查找一些VBA语句以了解它们的作用,但我试图避免任何过于复杂的事情。

有很多人回答问题,因此您无法对问题做出一致的回应。

如果您的问题对某人特别有意义,或者他们有一些合适的代码可以提供,那么当他们不应该根据本网站的理念时,他们可能会给您一个完整的答案。

如果您使用惹恼人们的短语,您将被忽略或得到粗鲁的回复。 “我可以做X吗?”在这里惹恼了很多人。你是网站的新手;你怎么知道你在冒犯他人?

我们不是要向任何想要它的人提供免费代码。这个网站是关于帮助其他程序员改进的程序员。站点规则明确要求您对如何解决问题有一个最小的了解。有些回答者会怜悯而忽视这条规则;大多数人不会。我们应该帮助您编写自己的新代码或改进现有代码;不要为你写。

你在一天之内问了三个问题,在我看来这是同一个问题的不同方面。但是,你似乎没有理解如何解决问题的第一部分,甚至你的问题都有部分。

我很欣赏让老板要求你解决问题的困难现在完全超出你的技能范围。因为互联网上有这么多,你的老板希望一切都可用。你找不到他的问题的确切解决方案,所以你没有努力尝试是你的错。 不,这不是你的错。这是一个独特的问题,那么为什么会有人编写并发布解决方案呢?我会外交而不是说我对你老板的想法。

我对您的问题的理解是:

  1. 您有大约100个文本文件,每个文件包含您要提取的一些信息。
  2. 要提取的信息是第67至76行。
  3. 您希望将此信息收集到工作表中。如果此工作表位于现有工作簿中,或者如果要将新信息添加到现有工作表中先前提取的信息下面,我认为您没有说过。
  4. 您没有说明如何安排信息。您是希望每个文件中的10行分布在单个工作表行中,还是每个工作表行需要一个文件行?
  5. 我的理解是你尚未得到第1步的解决方案。如果您不知道如何获取想要阅读的所有文件,那么有关提取第67行到第76行的要点很少。因此,让我们尝试解决第1部分。

    我尝试在StackOverflow和互联网上搜索相关代码。我对“如何阅读VBA文件夹中的所有工作簿”得到了最好的回复,但是新手将相关信息与噪声分开会很困难(不可能?)。

    对VBA没有或几乎没有任何了解,这使得在找到VBA时很难识别出你想要的东西。互联网有许多“Excel VBA教程”。一个大型图书馆或书店将有一个计算机部分,其中有一个装满了指导书的书架,其中一些将涵盖VBA。请投入一些时间进行背景研究。这笔投资将很快回报。

    这样的问题可能产生了有用的回应:

    我有一个包含100个文本文件的文件夹,我想逐个处理。我确信有些功能会有所帮助,但我找不到它们。

    这个问题非常重要,我相信有人会给出有用的答案。不要忘记接受这个答案,因为这给回答者带来了积分和声誉。您希望获得接受答案的人的声誉,以便人们想要回答您的问题。只要一个问题得到解答和接受,你就可以问另一个问题。您每天可以提出的问题数量没有限制。

    您也可以尝试打开VBA编辑器,选择帮助然后 Microsoft Visual Basic文档然后 Visual Basic语言参考然后功能。在此之下是按字母顺序列出的所有可用VBA功能。大多数与您当前的问题无关。你想要的是Dir或Dir $。它们看起来完全相同,但Dir $的效率略高。

    我不知道初学者如何找到另一种获取文件夹中文件列表的方法。您需要查看文件夹对象文件属性。如果您搜索文件属性的VBA帮助,您将获得一长串结果。一个是 Files属性(Visual Basic for Applications)。选择那将为您提供一个很好的相关代码。

    VBA帮助是一本字典。如果您不知道某个单词存在且您不知道如何拼写它,您将找不到该单词。您可以快速查看每个函数,方法和属性,并确定它们是否有趣。有些人对这种方法发誓,但我发现一本好书对我来说是一个更好的方法。你的选择。

    Dir功能是更老,更简单的方法。但是,对于问题的下一部分,您将需要文件系统对象,因此我将使用该方法。

    如果您还没有合适的工作簿,请在包含文本文件的文件夹中创建工作簿。您不必将工作簿放在同一个文件夹中,但如果您这样做会更容易,并且下面的宏假定它们位于同一个文件夹中。

    打开VB编辑器,创建一个新模块并将下面的代码复制到其中。

    Option Explicit
    Sub Test1()
    
      Dim FileSysObj As Object
      Dim FolderObj As Object
      Dim FileColl As Object
      Dim FileObj As Object
    
      Dim PathSearch As String
    
      ' This assumes the text files are in the same folder as the workbook holding the macro.
      ' Use PathSearch = "C:\ ..." if you would rather have the files in a different folder.
      PathSearch = ActiveWorkbook.Path
    
      Set FileSysObj = CreateObject("Scripting.FileSystemObject")
      Set FolderObj = FileSysObj.getfolder(PathSearch)
      Set FileColl = FolderObj.Files
    
      For Each FileObj In FileColl
        With FileObj
          If LCase(Right(.Name, 4)) = ".txt" Then
            Debug.Print .Name & "  " & .DateCreated & "  " & .Size & " bytes"
          End If
        End With
      Next
    
    End Sub
    

    此宏显示文件夹PathSearch中扩展名为“.txt”或“.TXT”的每个文件的列表。我已经包含了您不需要的创建日期和大小,以显示其他可用属性。此宏显示如何查找文件夹中所有文本文件的名称。这是您要求的第一部分的解决方案。

    您的要求的第2部分是打开每个文件,提取所选内容并关闭文件。

    处理文本文件有两种不同的方法。较旧的方法使用文件编号。例如,open语句是:

    Open pathname For mode [Access access] [lock] As [#]filenumber [Len=reclength]
    

    较新的方法使用文件对象:

    object.OpenAsTextStream([iomode, [format]])
    

    我将使用第二种方法,因为我想使用ReadAll方法。这提供文件不是太大很方便。如果你有足够的可用内存,你可以用ReadAll读取大文件,但如果你只想在开头附近有几行,那就不是很有效了。

    一旦您知道如何使用文件系统对象访问文件夹和文件列表,使用它们打开和访问文件就相对容易了。如果您试图通过提出一系列问题来获得解决方案,那么您应该尝试为第2部分编写自己的代码。如果您的代码失败,您可以发布一个寻求修复代码帮助的问题。这是最快速回答的问题类型。您的错误可能是一个简单的语法错误,有经验的程序员会立即发现。我将把你的解决方案提供给第2部分。

    复制并粘贴Sub Test1并修改其名称以创建Test2。

    您需要更多变量,因此请在Test2的顶部添加:

      Dim File As Object
      Dim FileAll As String
      Dim FileLine() As String
    

    在Test1中,我使用了With语句:

        With FileObj
          If LCase(Right(.Name, 4)) = ".txt" Then
            Debug.Print .Name & "  " & .DateCreated & "  " & .Size & " bytes"
          End If
        End With
    

    这比编写没有With声明的等效内容更容易:

        If LCase(Right(FileObj.Name, 4)) = ".txt" Then
          Debug.Print FileObj.Name & "  " & FileObj.DateCreated & "  " & FileObj.Size & " bytes"
        End If
    

    对于我的Test2,使用With语句可能仍然更容易,但对于Test3来说并不容易,因此我现在将删除With语句。

    For Each FileObj In FileColl替换为Next

      For Each FileObj In FileColl
        If LCase(Right(FileObj.Name, 4)) = ".txt" Then
          Set File = FileObj.OpenAsTextStream(1)      ' 1 means open in read mode
          FileAll = File.ReadAll
          File.Close
          FileLine = Split(FileAll, vbCr & vbLf)
          Debug.Print FileObj.Name & "  " & FileLine(0)
          Debug.Print FileObj.Name & "  " & FileLine(1)
        End If
      Next
    

    使用Test1,我会识别文件夹中的每个文本文件,并通过显示每个文件的名称来证明我已经这样做了。使用Test2,我已经扩展了一点宏。现在:

    • 打开每个文件。
    • 以字符串形式读取其内容。
    • 关闭文件。
    • 使用函数Split将该字符串拆分为多行。这假定这些文件使用CR LF作为换行符,这是Windows的标准。如果这个假设是假的,FileLine(0)将是整个文件,并且不会有FileLine(1)。下一个最有可能的换行是单独LF。
    • 显示文件的前两行以演示宏是否有效。

    如果实验无法帮助您找到正确的换行符或字符串,则可以提出如下问题:

    I have read a text file into a string and want to split it into lines.  I have tried:
    
        FileLine = Split(FileAll, vbCr & vbLf)
        FileLine = Split(FileAll, vbLf)
    
    but neither works.  Please suggest how I can determine the line break string.
    

    如果我看到这个问题,我会建议:

        Debug.Print Replace(Replace(Mid(FileAll, 1, 200), vbCr, "{cr}"), vbLf, "{lf}")
    

    这会将CR和LF转换为可打印的字符串。断线不太可能不是CR和LF的某种组合。您可以将此语句添加到Test2以查看它输出的内容。如果那次失败,我会回来做一个更复杂的诊断程序。

    Debug.Print是显示宏工作(或不工作)的一种非常简单的方法。它的一个明显的局限是立即窗口的大小有限,早期的线路可能会丢失,以便为以后的线路让路。我不确定限制是多少,但怀疑它不到200.在这种特殊情况下,看到最后200行左右就足以证明成功。在其他情况下,这是不够的。我将为我的下一个&#34;回答&#34;。

    添加一个可能的解决方案

    我们现在有一个宏来解决您的要求的第一部分1和部分第2部分。

    我希望你能够在不提出问题的情况下完成第2部分。既然你需要的只是一个简单的For-Loop,我相信你会发现很难构建一个任何人都会认真对待的问题。

    我希望你能意识到你需要一个新的变量:

      Dim InxLine As Long
    

    并用以下内容替换两个Debug.Print语句:

          For InxLine = 66 To 75
            Debug.Print FileObj.Name & "  " & FileLine(InxLine)
          Next
    

    我原本以为你已经注意到文件的第一行是在FileLine(0)中,这就是我输出66到75行的原因。

    每个文件有10行,所有内容都不可能适合立即窗口。正如我所说,这在这种情况下并不重要,但可能在另一种情况下。可能最好的选择是拥有诊断文件。在宏的开头创建一个文本文件,在运行期间写入诊断信息然后关闭它。更简单的技术是添加另一个变量:

      Dim Count as Long
    

    并将上面的For-Loop替换为:

          For InxLine = 66 To 75
            Debug.Print FileObj.Name & "  " & FileLine(InxLine)
            Count = Count + 1
          Next
          If Count > 100 Then
            Debug.Assert False
            Count = 0
          End If
    

    Debug.Assert是非常有用的诊断辅助工具。正常使用可能是Debug.Assert myVar > 0。 myVar在我的宏中的某个地方被破坏但是我无法找到它。我将Debug.Assert myVar >= 0放在我的宏中,只要myVar具有允许我调查的负值,它就会停止。使用Debug.Assert False时,宏将始终停止。这意味着每100行左右,宏将停止以允许我检查立即窗口。单击 F5 将重新启动宏。

    通过这个最新的更改,宏输出感兴趣的行到立即窗口,以证明它可以找到感兴趣的行。

    最后一步是将感兴趣的行输出到工作表。正如我所说,你没有说什么工作表或如何组织行。有许多答案可以向您展示如何创建新工作簿或打开现有工作簿。如果现有工作簿中有答案显示如何查找工作表中任何现有数据的底部,则可以添加新数据。因此,我将做最简单的方法来清除工作表&#34; Sheet1&#34;当前工作簿并将数据写入其中。

    添加两个新变量:

      Dim ColCrnt As Long
      Dim RowCrnt As Long
    

    在宏顶部附近添加:

      With Worksheets("Sheet1")
        ' Clear the worksheet
        .Cells.EntireRow.Delete
        ' Create a heading row
        RowCrnt = 1
        ColCrnt = 1
        .Cells(RowCrnt, ColCrnt).Value = "Filename"
        For ColCrnt = 2 To 11
          .Cells(RowCrnt, ColCrnt).Value = "Line " & ColCrnt + 65
        Next
        .Range("A1:K1").Font.Bold = True
        RowCrnt = 2
      End With
    

    替换:

          For InxLine = 66 To 75
            Debug.Print FileObj.Name & "  " & FileLine(InxLine)
          Next
    

          With Worksheets("Sheet1")
            .Cells(RowCrnt, 1).Value = FileObj.Name
            For ColCrnt = 2 To 11
             .Cells(RowCrnt, ColCrnt).Value = FileLine(ColCrnt + 64)
            Next
          End With
          RowCrnt = RowCrnt + 1
    

    在底部添加:

      With Worksheets("Sheet1")
        .Columns.AutoFit
      End With
    

    当你运行这个宏时,它应该大致做你想要的。

    <强>摘要

    您必须获得VBA的一般基础。如果没有这个,你试图从这个或其他网站上的一些脚本构建一个宏,就好像用一种语言构建一个你不知道的语言的字母。

    我试图表明将您的要求分解为小步骤的重要性。获得小问题的答案通常很容易。

    从您在Internet上或Visual Basic帮助中找到的代码片段构建一系列宏:

    • Macro 1证明您可以实现您的要求的第1步。
    • Macro 2证明您可以实现您的要求的第1步和第2步。
    • Macro 3证明您可以实现您的要求的第1,2和3步。
    • ::
    • 宏n符合您的要求。

    我希望这有帮助。祝你好运。

答案 1 :(得分:2)

使用您的代码,有几个问题,1不是有效的变量名称(标识符)。变量名不能以数字或各种特殊字符开头,也不能包含空格。您还缺少示例代码中的End Sub,但我相信您已经在IDE中使用了它,因为如果没有它,VBA甚至都不会编译。我在下面写了一段代码,满足了能够逐行读取文件内容的要求。如果您需要打开第二个文件,则只需复制从Open开始并以Close #A结尾的代码。

Sub ImportFile()
    Dim J As Long, K As Long
    Dim FileNum As Integer
    Dim A As String
    A = FreeFile()
    Open "C:\Users\UserName\Desktop\movies" For Input As #A
    While Not EOF(A)
        Line Input #A, FileLine
    Wend
    Close #A
End Sub

StackOverflow通常不是为您编写代码的地方,但我们很乐意帮助您理清具体问题。如果您能够逐行读取每个文件后有更多问题,则应该发布另一个问题,说明具体问题并尝试解决问题。