将一个 CSV 文件读入数组,使用 Excel VBA。

huangapple go评论115阅读模式
英文:

Read a csv file into an array using Excel VBA

问题

I suspect both RowsArray and ColumnsArray need to be redimensioned, but how do I know the dimensions before splitting them?

我怀疑RowsArray和ColumnsArray都需要重新调整维度,但在拆分它们之前如何知道维度呢?

英文:

I am unable to figure out how to read in a simple csv file using Excel VBA.

If I want to open and read a csv file, this statement should suffice, as long as the filepath is a valid string?

  1. ' Open file and read contents
  2. Open FilePath For Input As #1
  3. FileContent = Input(LOF(1), 1)
  4. Close #1

Then, I want to create a two dimensional array, with rows and columns. I would think this should do the job, but it does not.

  1. ' Split file content into rows
  2. RowsArray = Split(FileContent, vbCrLf)
  3. ' Split rows into columns
  4. Dim i As Long
  5. For i = LBound(RowsArray) To UBound(RowsArray)
  6. ColumnsArray = Split(RowsArray(i), ",")
  7. Next i

It does not give an error, but the columns array is empty,

The whole function is here:

  1. Public Function ReadCSVFileInToArray(FilePath)
  2. ' Define variables
  3. Dim FileContent As String
  4. Dim RowsArray() As String
  5. ' Open file and read contents
  6. Open FilePath For Input As #1
  7. FileContent = Input(LOF(1), 1)
  8. Close #1
  9. ' Split file content into rows
  10. RowsArray = Split(FileContent, vbCrLf)
  11. ' Split rows into columns
  12. Dim i As Long
  13. For i = LBound(RowsArray) To UBound(RowsArray)
  14. ColumnsArray = Split(RowsArray(i), ",")
  15. Next i
  16. ReadCSVFileInToArray = ColumnsArray
  17. End Function

I suspect both RowsArray and ColumnsArray need to be redimensioned, but how do I know the dimensions before splitting them?

It seems like this should be easy, so I'm clearly not understanding something. I can't even find an intelligible explanation on the web.

答案1

得分: 2

以下是您要翻译的内容:

返回CSV文件的值为2D数组

示例(用法)

  1. Sub Test()
  2. Const FILE_PATH As String = "C:\Test\Test.csv"
  3. Const ROW_DELIMITER As String = vbCrLf ' vbLf
  4. Const COL_DELIMITER As String = "," ' ";"
  5. Dim sArr: sArr = TextFileToArray(FILE_PATH, ROW_DELIMITER)
  6. If IsEmpty(sArr) Then Exit Sub
  7. Dim Data(): Data = GetSplitArray(sArr, COL_DELIMITER)
  8. ' 打印到即时窗口(Ctrl+G)。
  9. PrintData Data
  10. ' 写入工作表。
  11. 'With Sheet1.Range("A1")
  12. ' .Resize(UBound(Data, 1), UBound(Data, 2)).Value = Data
  13. 'End With
  14. End Sub
  • 您可以在这里找到PrintData过程。

将行转换为1D数组

  1. ' Purpose: 返回文本文件的每一行作为一维零基数组的元素。
  2. Function TextFileToArray( _
  3. ByVal FilePath As String, _
  4. Optional ByVal LineSeparator As String = vbLf) _
  5. As Variant
  6. Dim TextFile As Long: TextFile = FreeFile
  7. Dim sArr() As String
  8. Open FilePath For Input Access Read As TextFile
  9. On Error Resume Next
  10. sArr = Split(Input(LOF(TextFile), TextFile), LineSeparator)
  11. On Error GoTo 0
  12. Close TextFile
  13. Dim n As Long
  14. For n = UBound(sArr) To LBound(sArr) Step -1
  15. If Len(sArr(n)) > 0 Then Exit For
  16. Next n
  17. If n < LBound(sArr) Then Exit Function
  18. If n < UBound(sArr) Then ReDim Preserve sArr(0 To n)
  19. TextFileToArray = sArr
  20. End Function

将1D数组拆分为2D数组

  1. ' Purpose: 返回一维数组的每个元素的拆分值
  2. ' 在二维基于一的数组的一行中。
  3. Function GetSplitArray( _
  4. ByVal SourceArray As Variant, _
  5. Optional ByVal ColumnDelimiter As String = ",") _
  6. As Variant
  7. Dim rDiff As Long: rDiff = 1 - LBound(SourceArray)
  8. Dim rCount As Long: rCount = UBound(SourceArray) + rDiff
  9. Dim cCount As Long: cCount = 1
  10. Dim Data(): ReDim Data(1 To rCount, 1 To cCount)
  11. Dim rArr() As String, r As Long, c As Long, cc As Long, rString As String
  12. For r = 1 To rCount
  13. rString = SourceArray(r - rDiff)
  14. If Len(rString) > 0 Then
  15. rArr = Split(rString, ColumnDelimiter)
  16. cc = UBound(rArr) + 1
  17. If cc > cCount Then
  18. cCount = cc
  19. ReDim Preserve Data(1 To rCount, 1 To cCount)
  20. End If
  21. For c = 1 To cc
  22. Data(r, c) = rArr(c - 1)
  23. Next c
  24. End If
  25. Next r
  26. GetSplitArray = Data
  27. End Function

请告诉我您需要进一步的翻译或其他帮助。

英文:

Return the Values of a CSV File in a 2D Array

An Example (Usage)

  1. Sub Test()
  2. Const FILE_PATH As String = &quot;C:\Test\Test.csv&quot;
  3. Const ROW_DELIMITER As String = vbCrLf &#39; vbLf
  4. Const COL_DELIMITER As String = &quot;,&quot; &#39; &quot;;&quot;
  5. Dim sArr: sArr = TextFileToArray(FILE_PATH, ROW_DELIMITER)
  6. If IsEmpty(sArr) Then Exit Sub
  7. Dim Data(): Data = GetSplitArray(sArr, COL_DELIMITER)
  8. &#39; Print to the Immediate window (Ctrl+G).
  9. PrintData Data
  10. &#39; Write to the worksheet.
  11. &#39;With Sheet1.Range(&quot;A1&quot;)
  12. &#39; .Resize(UBound(Data, 1), UBound(Data, 2)).Value = Data
  13. &#39;End With
  14. End Sub
  • You can find the PrintData procedure here.

Rows to 1D Array

<!-- language: lang-vb -->

  1. &#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;
  2. &#39; Purpose: Returns each line of a text file in an element
  3. &#39; of a 1D zero-based array.
  4. &#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;
  5. Function TextFileToArray( _
  6. ByVal FilePath As String, _
  7. Optional ByVal LineSeparator As String = vbLf) _
  8. As Variant
  9. Dim TextFile As Long: TextFile = FreeFile
  10. Dim sArr() As String
  11. Open FilePath For Input Access Read As TextFile
  12. On Error Resume Next
  13. sArr = Split(Input(LOF(TextFile), TextFile), LineSeparator)
  14. On Error GoTo 0
  15. Close TextFile
  16. Dim n As Long
  17. For n = UBound(sArr) To LBound(sArr) Step -1
  18. If Len(sArr(n)) &gt; 0 Then Exit For
  19. Next n
  20. If n &lt; LBound(sArr) Then Exit Function
  21. If n &lt; UBound(sArr) Then ReDim Preserve sArr(0 To n)
  22. TextFileToArray = sArr
  23. End Function

Split 1D Array to 2D Array

<!-- language: lang-vb -->

  1. &#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;
  2. &#39; Purpose: Returns the split values of each element of a 1D array
  3. &#39; in a row of a 2D one-based array.
  4. &#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;
  5. Function GetSplitArray( _
  6. ByVal SourceArray As Variant, _
  7. Optional ByVal ColumnDelimiter As String = &quot;,&quot;) _
  8. As Variant
  9. Dim rDiff As Long: rDiff = 1 - LBound(SourceArray)
  10. Dim rCount As Long: rCount = UBound(SourceArray) + rDiff
  11. Dim cCount As Long: cCount = 1
  12. Dim Data(): ReDim Data(1 To rCount, 1 To cCount)
  13. Dim rArr() As String, r As Long, c As Long, cc As Long, rString As String
  14. For r = 1 To rCount
  15. rString = SourceArray(r - rDiff)
  16. If Len(rString) &gt; 0 Then
  17. rArr = Split(rString, ColumnDelimiter)
  18. cc = UBound(rArr) + 1
  19. If cc &gt; cCount Then
  20. cCount = cc
  21. ReDim Preserve Data(1 To rCount, 1 To cCount)
  22. End If
  23. For c = 1 To cc
  24. Data(r, c) = rArr(c - 1)
  25. Next c
  26. End If
  27. Next r
  28. GetSplitArray = Data
  29. End Function

答案2

得分: 1

让Excel来完成这项工作

  1. Public Function ReadCSVFileInToArray(FilePath)
  2. Dim wb As Workbook
  3. Application.ScreenUpdating = False
  4. Set wb = Workbooks.Open(FilePath, ReadOnly:=True)
  5. ReadCSVFileInToArray = wb.Sheets(1).UsedRange.Value
  6. wb.Close
  7. Application.ScreenUpdating = True
  8. End Function

将第一行拆分以获取第二维度。

  1. Public Function ReadCSVFileInToArray(FilePath)
  2. ' 定义变量
  3. Dim FileContent, RowsArray, ColumnsArray
  4. Dim ar()
  5. ' 打开文件并读取内容
  6. Open FilePath For Input As #1
  7. FileContent = Input(LOF(1), 1)
  8. Close #1
  9. ' 拆分文件内容为行
  10. RowsArray = Split(FileContent, vbCrLf)
  11. ' 拆分标题行为列
  12. ColumnsArray = Split(RowsArray(0), ",")
  13. ReDim ar(1 To UBound(RowsArray) + 1, 1 To UBound(ColumnsArray) + 1)
  14. ' 拆分行为列
  15. Dim i As Long, j As Long
  16. For i = LBound(RowsArray) To UBound(RowsArray)
  17. ColumnsArray = Split(RowsArray(i), ",")
  18. For j = 0 To UBound(ColumnsArray)
  19. ar(i + 1, j + 1) = ColumnsArray(j)
  20. Next
  21. Next i
  22. ReadCSVFileInToArray = ar
  23. End Function
英文:

Let excel do the work

  1. Public Function ReadCSVFileInToArray(FilePath)
  2. Dim wb As Workbook
  3. Application.ScreenUpdating = False
  4. Set wb = Workbooks.Open(FilePath, ReadOnly:=True)
  5. ReadCSVFileInToArray = wb.Sheets(1).UsedRange.Value
  6. wb.Close
  7. Application.ScreenUpdating = True
  8. End Function

Split the first line to get the 2nd dimension.

  1. Public Function ReadCSVFileInToArray(FilePath)
  2. &#39; Define variables
  3. Dim FileContent, RowsArray, ColumnsArray
  4. Dim ar()
  5. &#39; Open file and read contents
  6. Open FilePath For Input As #1
  7. FileContent = Input(LOF(1), 1)
  8. Close #1
  9. &#39; Split file content into rows
  10. RowsArray = Split(FileContent, vbCrLf)
  11. &#39; Split header row into columns
  12. ColumnsArray = Split(RowsArray(0), &quot;,&quot;)
  13. ReDim ar(1 To UBound(RowsArray) + 1, 1 To UBound(ColumnsArray) + 1)
  14. &#39; Split rows into columns
  15. Dim i As Long, j As Long
  16. For i = LBound(RowsArray) To UBound(RowsArray)
  17. ColumnsArray = Split(RowsArray(i), &quot;,&quot;)
  18. For j = 0 To UBound(ColumnsArray)
  19. ar(i + 1, j + 1) = ColumnsArray(j)
  20. Next
  21. Next i
  22. ReadCSVFileInToArray = ar
  23. End Function
  24. </details>
  25. # 答案3
  26. **得分**: 1
  27. I adjusted your code and added explanations (see the comments) in the code as well:
  28. ```vba
  29. Option Explicit
  30. Public Function ReadCSVFileInToArray(FilePath)
  31. ' Define variables
  32. Dim FileContent As String
  33. Dim RowsArray() As String
  34. Dim ColumnsArray() As String
  35. Dim vDat As Variant
  36. ' Open file and read contents
  37. Open FilePath For Input As #1
  38. FileContent = Input(LOF(1), 1)
  39. Close #1
  40. ' Split file content into rows
  41. RowsArray = Split(FileContent, vbCrLf)
  42. ' Redim the 1st dimension to have space for all rows
  43. Dim rowNo As Long
  44. rowNo = UBound(RowsArray)
  45. ReDim ColumnsArray(0 To rowNo, 0)
  46. ' Split rows into columns
  47. Dim i As Long, j As Long
  48. For i = LBound(RowsArray) To UBound(RowsArray)
  49. vDat = Split(RowsArray(i), ";")
  50. ' This will skip lines with no data especially last one if it only contains a CRLF
  51. If UBound(vDat) > 0 Then
  52. ' Redim the 2nd dimension to have space for all columns
  53. Dim colNo As Long
  54. colNo = UBound(vDat)
  55. ' Redim will preserve and fortunately we only have to change the last dimension
  56. ' If you use the Preserve keyword, you can resize only the last array dimension
  57. ' and you can't change the number of dimensions at all.
  58. ReDim Preserve ColumnsArray(rowNo, colNo)
  59. ' you have to copy element by element
  60. For j = 0 To colNo
  61. ColumnsArray(i, j) = vDat(j)
  62. Next j
  63. End If
  64. Next i
  65. ReadCSVFileInToArray = ColumnsArray
  66. End Function
  67. ```
  68. You can test it with:
  69. ```vba
  70. Sub testIt()
  71. Dim vDat As Variant
  72. vDat = ReadCSVFileInToArray("filepath")
  73. Dim rg As Range
  74. Set rg = Range("A1")
  75. ' Resize the range to the size of the array
  76. Set rg = rg.Resize(UBound(vDat, 1), UBound(vDat, 2))
  77. rg = vDat
  78. End Sub
  79. ```
  80. The better way to import text files into Excel is Power Query though because you have more control regarding data types, etc.
  81. [1]: https://learn.microsoft.com/en-us/power-query/connectors/text-csv
  82. [2]: https://learn.microsoft.com/en-us/power-query/
  83. <details>
  84. <summary>英文:</summary>
  85. I adjusted your code and added explanations (see the comments) in the code as well
  86. Option Explicit
  87. Public Function ReadCSVFileInToArray(FilePath)
  88. &#39; Define variables
  89. Dim FileContent As String
  90. Dim RowsArray() As String
  91. Dim ColumnsArray() As String
  92. Dim vDat As Variant
  93. &#39; Open file and read contents
  94. Open FilePath For Input As #1
  95. FileContent = Input(LOF(1), 1)
  96. Close #1
  97. &#39; Split file content into rows
  98. RowsArray = Split(FileContent, vbCrLf)
  99. &#39; Redim the 1st dimension to have space for all rows
  100. Dim rowNo As Long
  101. rowNo = UBound(RowsArray)
  102. ReDim ColumnsArray(0 To rowNo, 0)
  103. &#39; Split rows into columns
  104. Dim i As Long, j As Long
  105. For i = LBound(RowsArray) To UBound(RowsArray)
  106. vDat = Split(RowsArray(i), &quot;;&quot;)
  107. &#39; This will skip lines with no data especially last one if it only contains a CRLF
  108. If UBound(vDat) &gt; 0 Then
  109. &#39; Redim the 2nd dimension to have space for all columns
  110. Dim colNo As Long
  111. colNo = UBound(vDat)
  112. &#39; Redim will preserve and fortunately we only have to change the last dimension
  113. &#39; If you use the Preserve keyword, you can resize only the last array dimension
  114. &#39; and you can&#39;t change the number of dimensions at all.
  115. ReDim Preserve ColumnsArray(rowNo, colNo)
  116. &#39; you have to copy element by element
  117. For j = 0 To colNo
  118. ColumnsArray(i, j) = vDat(j)
  119. Next j
  120. End If
  121. Next i
  122. ReadCSVFileInToArray = ColumnsArray
  123. End Function
  124. You can test it with
  125. Sub testIt()
  126. Dim vDat As Variant
  127. vDat = ReadCSVFileInToArray(&quot;filepath&quot;)
  128. Dim rg As Range
  129. Set rg = Range(&quot;A1&quot;)
  130. &#39; Resize the range to the size of the array
  131. Set rg = rg.Resize(UBound(vDat, 1), UBound(vDat, 2))
  132. rg = vDat
  133. End Sub
  134. The better way to [import text files][1] into Excel is [Powerquery][2] though because you have more control regarding data type etc.
  135. [1]: https://learn.microsoft.com/en-us/power-query/connectors/text-csv
  136. [2]: https://learn.microsoft.com/en-us/power-query/
  137. </details>

huangapple
  • 本文由 发表于 2023年5月8日 00:06:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/76194971.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定