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

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

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?

 ' Open file and read contents 
    Open FilePath For Input As #1 
    FileContent = Input(LOF(1), 1) 
    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.

' Split file content into rows 
RowsArray = Split(FileContent, vbCrLf) 
 
' Split rows into columns 
Dim i As Long 
For i = LBound(RowsArray) To UBound(RowsArray) 
    ColumnsArray = Split(RowsArray(i), ",") 
Next i 

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

The whole function is here:

Public Function ReadCSVFileInToArray(FilePath) 
     
    ' Define variables 
    Dim FileContent As String 
    Dim RowsArray() As String 
   
    ' Open file and read contents 
    Open FilePath For Input As #1 
    FileContent = Input(LOF(1), 1) 
    Close #1 
     
    ' Split file content into rows 
    RowsArray = Split(FileContent, vbCrLf) 
     
    ' Split rows into columns 
    Dim i As Long 
    For i = LBound(RowsArray) To UBound(RowsArray) 
        ColumnsArray = Split(RowsArray(i), ",") 
    Next i 
    ReadCSVFileInToArray = ColumnsArray 
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数组

示例(用法)

Sub Test()

    Const FILE_PATH As String = "C:\Test\Test.csv"
    Const ROW_DELIMITER As String = vbCrLf ' vbLf
    Const COL_DELIMITER As String = "," ' ";"

    Dim sArr: sArr = TextFileToArray(FILE_PATH, ROW_DELIMITER)
    If IsEmpty(sArr) Then Exit Sub

    Dim Data(): Data = GetSplitArray(sArr, COL_DELIMITER)

    ' 打印到即时窗口(Ctrl+G)。
    PrintData Data

    ' 写入工作表。
    'With Sheet1.Range("A1")
    '    .Resize(UBound(Data, 1), UBound(Data, 2)).Value = Data
    'End With

End Sub
  • 您可以在这里找到PrintData过程。

将行转换为1D数组

' Purpose:      返回文本文件的每一行作为一维零基数组的元素。
Function TextFileToArray( _
    ByVal FilePath As String, _
    Optional ByVal LineSeparator As String = vbLf) _
As Variant

    Dim TextFile As Long: TextFile = FreeFile

    Dim sArr() As String

    Open FilePath For Input Access Read As TextFile
        On Error Resume Next
            sArr = Split(Input(LOF(TextFile), TextFile), LineSeparator)
        On Error GoTo 0
    Close TextFile

    Dim n As Long

    For n = UBound(sArr) To LBound(sArr) Step -1
        If Len(sArr(n)) > 0 Then Exit For
    Next n

    If n < LBound(sArr) Then Exit Function
    If n < UBound(sArr) Then ReDim Preserve sArr(0 To n)

    TextFileToArray = sArr

End Function

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

' Purpose:      返回一维数组的每个元素的拆分值
'               在二维基于一的数组的一行中。
Function GetSplitArray( _
    ByVal SourceArray As Variant, _
    Optional ByVal ColumnDelimiter As String = ",") _
As Variant

    Dim rDiff As Long: rDiff = 1 - LBound(SourceArray)

    Dim rCount As Long: rCount = UBound(SourceArray) + rDiff
    Dim cCount As Long: cCount = 1

    Dim Data(): ReDim Data(1 To rCount, 1 To cCount)

    Dim rArr() As String, r As Long, c As Long, cc As Long, rString As String

    For r = 1 To rCount
        rString = SourceArray(r - rDiff)
        If Len(rString) > 0 Then
            rArr = Split(rString, ColumnDelimiter)
            cc = UBound(rArr) + 1
            If cc > cCount Then
                cCount = cc
                ReDim Preserve Data(1 To rCount, 1 To cCount)
            End If
            For c = 1 To cc
                Data(r, c) = rArr(c - 1)
            Next c
        End If
    Next r

    GetSplitArray = Data

End Function

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

英文:

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

An Example (Usage)

Sub Test()

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

Rows to 1D Array

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

&#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;
&#39; Purpose:      Returns each line of a text file in an element
&#39;               of a 1D zero-based array.
&#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;
Function TextFileToArray( _
    ByVal FilePath As String, _
    Optional ByVal LineSeparator As String = vbLf) _
As Variant

    Dim TextFile As Long: TextFile = FreeFile
    
    Dim sArr() As String
    
    Open FilePath For Input Access Read As TextFile
        On Error Resume Next
            sArr = Split(Input(LOF(TextFile), TextFile), LineSeparator)
        On Error GoTo 0
    Close TextFile

    Dim n As Long
    
    For n = UBound(sArr) To LBound(sArr) Step -1
        If Len(sArr(n)) &gt; 0 Then Exit For
    Next n
    
    If n &lt; LBound(sArr) Then Exit Function
    If n &lt; UBound(sArr) Then ReDim Preserve sArr(0 To n)
    
    TextFileToArray = sArr

End Function

Split 1D Array to 2D Array

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

&#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;
&#39; Purpose:      Returns the split values of each element of a 1D array
&#39;               in a row of a 2D one-based array.
&#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;
Function GetSplitArray( _
    ByVal SourceArray As Variant, _
    Optional ByVal ColumnDelimiter As String = &quot;,&quot;) _
As Variant

    Dim rDiff As Long: rDiff = 1 - LBound(SourceArray)

    Dim rCount As Long: rCount = UBound(SourceArray) + rDiff
    Dim cCount As Long: cCount = 1
    
    Dim Data(): ReDim Data(1 To rCount, 1 To cCount)
    
    Dim rArr() As String, r As Long, c As Long, cc As Long, rString As String
    
    For r = 1 To rCount
        rString = SourceArray(r - rDiff)
        If Len(rString) &gt; 0 Then
            rArr = Split(rString, ColumnDelimiter)
            cc = UBound(rArr) + 1
            If cc &gt; cCount Then
                cCount = cc
                ReDim Preserve Data(1 To rCount, 1 To cCount)
            End If
            For c = 1 To cc
                Data(r, c) = rArr(c - 1)
            Next c
        End If
    Next r

    GetSplitArray = Data

End Function

答案2

得分: 1

让Excel来完成这项工作

Public Function ReadCSVFileInToArray(FilePath)

    Dim wb As Workbook
    Application.ScreenUpdating = False
    Set wb = Workbooks.Open(FilePath, ReadOnly:=True)
    ReadCSVFileInToArray = wb.Sheets(1).UsedRange.Value
    wb.Close
    Application.ScreenUpdating = True

End Function

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

Public Function ReadCSVFileInToArray(FilePath)

    ' 定义变量
    Dim FileContent, RowsArray, ColumnsArray
    Dim ar()

    ' 打开文件并读取内容
    Open FilePath For Input As #1
    FileContent = Input(LOF(1), 1)
    Close #1

    ' 拆分文件内容为行
    RowsArray = Split(FileContent, vbCrLf)

    ' 拆分标题行为列
    ColumnsArray = Split(RowsArray(0), ",")

    ReDim ar(1 To UBound(RowsArray) + 1, 1 To UBound(ColumnsArray) + 1)

    ' 拆分行为列
    Dim i As Long, j As Long
    For i = LBound(RowsArray) To UBound(RowsArray)
        ColumnsArray = Split(RowsArray(i), ",")
        For j = 0 To UBound(ColumnsArray)
            ar(i + 1, j + 1) = ColumnsArray(j)
        Next
    Next i
    ReadCSVFileInToArray = ar

End Function
英文:

Let excel do the work

Public Function ReadCSVFileInToArray(FilePath)

    Dim wb As Workbook
    Application.ScreenUpdating = False
    Set wb = Workbooks.Open(FilePath, ReadOnly:=True)
    ReadCSVFileInToArray = wb.Sheets(1).UsedRange.Value
    wb.Close
    Application.ScreenUpdating = True

End Function

Split the first line to get the 2nd dimension.

Public Function ReadCSVFileInToArray(FilePath)
     
    &#39; Define variables
    Dim FileContent, RowsArray, ColumnsArray
    Dim ar()
   
    &#39; Open file and read contents
    Open FilePath For Input As #1
    FileContent = Input(LOF(1), 1)
    Close #1
     
    &#39; Split file content into rows
    RowsArray = Split(FileContent, vbCrLf)
    
    &#39; Split header row into columns
    ColumnsArray = Split(RowsArray(0), &quot;,&quot;)
     
    ReDim ar(1 To UBound(RowsArray) + 1, 1 To UBound(ColumnsArray) + 1)
     
    &#39; Split rows into columns
    Dim i As Long, j As Long
    For i = LBound(RowsArray) To UBound(RowsArray)
        ColumnsArray = Split(RowsArray(i), &quot;,&quot;)
        For j = 0 To UBound(ColumnsArray)
            ar(i + 1, j + 1) = ColumnsArray(j)
        Next
    Next i
    ReadCSVFileInToArray = ar
   
End Function

</details>



# 答案3
**得分**: 1

I adjusted your code and added explanations (see the comments) in the code as well:

```vba
Option Explicit

Public Function ReadCSVFileInToArray(FilePath)

    ' Define variables
    Dim FileContent As String
    Dim RowsArray() As String
    Dim ColumnsArray() As String
    Dim vDat As Variant

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

    ' Split file content into rows
    RowsArray = Split(FileContent, vbCrLf)

    ' Redim the 1st dimension to have space for all rows
    Dim rowNo As Long
    rowNo = UBound(RowsArray)
    ReDim ColumnsArray(0 To rowNo, 0)

    ' Split rows into columns
    Dim i As Long, j As Long
    For i = LBound(RowsArray) To UBound(RowsArray)
        vDat = Split(RowsArray(i), ";")

        ' This will skip lines with no data especially last one if it only contains a CRLF
        If UBound(vDat) > 0 Then

            ' Redim the 2nd dimension to have space for all columns
            Dim colNo As Long
            colNo = UBound(vDat)
            ' Redim will preserve and fortunately we only have to change the last dimension
            ' If you use the Preserve keyword, you can resize only the last array dimension
            ' and you can't change the number of dimensions at all.
            ReDim Preserve ColumnsArray(rowNo, colNo)

            ' you have to copy element by element
            For j = 0 To colNo
                ColumnsArray(i, j) = vDat(j)
            Next j

        End If
    Next i

    ReadCSVFileInToArray = ColumnsArray
End Function
```

You can test it with:

```vba
Sub testIt()
Dim vDat As Variant

    vDat = ReadCSVFileInToArray("filepath")
    Dim rg As Range
    Set rg = Range("A1")
    ' Resize the range to the size of the array
    Set rg = rg.Resize(UBound(vDat, 1), UBound(vDat, 2))
    rg = vDat
End Sub
```

The better way to import text files into Excel is Power Query though because you have more control regarding data types, etc.

[1]: https://learn.microsoft.com/en-us/power-query/connectors/text-csv
[2]: https://learn.microsoft.com/en-us/power-query/

<details>
<summary>英文:</summary>

I adjusted your code and added explanations (see the comments) in the code as well

    Option Explicit
    
    Public Function ReadCSVFileInToArray(FilePath)
         
        &#39; Define variables
        Dim FileContent As String
        Dim RowsArray() As String
        Dim ColumnsArray() As String
        Dim vDat As Variant
       
        &#39; Open file and read contents
        Open FilePath For Input As #1
        FileContent = Input(LOF(1), 1)
        Close #1
         
        &#39; Split file content into rows
        RowsArray = Split(FileContent, vbCrLf)
        
        &#39; Redim the 1st dimension to have space for all rows
        Dim rowNo As Long
        rowNo = UBound(RowsArray)
        ReDim ColumnsArray(0 To rowNo, 0)
         
        &#39; Split rows into columns
        Dim i As Long, j As Long
        For i = LBound(RowsArray) To UBound(RowsArray)
            vDat = Split(RowsArray(i), &quot;;&quot;)
            
            &#39; This will skip lines with no data especially last one if it only contains a CRLF
            If UBound(vDat) &gt; 0 Then
                
                &#39; Redim the 2nd dimension to have space for all columns
                Dim colNo As Long
                colNo = UBound(vDat)
                &#39; Redim will preserve and fortunately we only have to change the last dimension
                &#39; If you use the Preserve keyword, you can resize only the last array dimension
                &#39; and you can&#39;t change the number of dimensions at all.
                ReDim Preserve ColumnsArray(rowNo, colNo)
    
                &#39; you have to copy element by element
                For j = 0 To colNo
                    ColumnsArray(i, j) = vDat(j)
                Next j
                
            End If
        Next i
        
        ReadCSVFileInToArray = ColumnsArray
    End Function


You can test it with 

    Sub testIt()
    Dim vDat As Variant
    
        vDat = ReadCSVFileInToArray(&quot;filepath&quot;)
        Dim rg As Range
        Set rg = Range(&quot;A1&quot;)
        &#39; Resize the range to the size of the array
        Set rg = rg.Resize(UBound(vDat, 1), UBound(vDat, 2))
        rg = vDat
    End Sub

The better way to [import text files][1] into Excel is [Powerquery][2] though because you have more control regarding data type etc.


  [1]: https://learn.microsoft.com/en-us/power-query/connectors/text-csv
  [2]: https://learn.microsoft.com/en-us/power-query/

</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:

确定