【问题标题】:Can you directly write the contents of an array in excel VBA to a CSV file?你可以直接将excel VBA中的数组内容写入CSV文件吗?
【发布时间】:2022-01-12 16:12:49
【问题描述】:

我有一些代码可以将表格加载到数组中,进行一些计算,创建新工作表,将更改后的数组写入新工作表,并将新工作表保存为 CSV。

我需要一个 CSV,因为这是目标系统接受的唯一格式。

我想知道是否可以直接将数组写入 CSV,跳过 2 个步骤。

通过我的研究,我从THIS POST 找到了以下代码,但是我无法让它工作。

' SaveAsCSV saves an array as csv file. Choosing a delimiter different as a comma, is optional.
'
' Syntax:
' SaveAsCSV dMyArray, sMyFileName, [sMyDelimiter]
'
' Examples:
' SaveAsCSV dChrom, app.path & "\Demo.csv"       --> comma as delimiter
' SaveAsCSV dChrom, app.path & "\Demo.csv", ";"  --> semicolon as delimiter
'
' Rev. 1.00 [8 jan 2003]
' written by P. Wester
' wester@kpd.nl


Public Sub SaveAsCSV(MyArray() As Variant, sFilename As String, Optional sDelimiter As String = ",")

Dim n As Long 'counter
Dim M As Long 'counter
Dim sCSV As String 'csv string to print

On Error GoTo ErrHandler_SaveAsCSV


'check extension and correct if needed
If InStr(sFilename, ".csv") = 0 Then
  sFilename = sFilename & ".csv"
Else
  While (Len(sFilename) - InStr(sFilename, ".csv")) > 3
    sFilename = Left(sFilename, Len(sFilename) - 1)
  Wend
End If

'If MultiDimensional(MyArray()) = False Then '1 dimension

  'save the file
'  Open sFileName For Output As #7
'  For n = 0 To UBound(MyArray(), 1)
'    Print #7, Format(MyArray(n, 0), "0.000000E+00")
'  Next n
'  Close #7

'Else 'more dimensional

  'save the file
  Open sFilename For Output As #7
  For n = 1 To UBound(MyArray(), 1)
    sCSV = ""
    For M = 1 To UBound(MyArray(), 2)
      sCSV = sCSV & Format(MyArray(n, M)) & sDelimiter
    Next M
    sCSV = Left(sCSV, Len(sCSV) - 1) 'remove last Delimiter
    Print #7, sCSV
  Next n
  Close #7

'End If

Exit Sub


ErrHandler_SaveAsCSV:
  Close #7

使用这种语法

    SaveAsCSV arOut, Application.ActiveWorkbook.Path & "\Demo.csv"

我在该行收到此错误。类型不匹配:需要数组或用户定义类型。 我可以通过编辑这一行并删除括号来解决这个问题。

Public Sub SaveAsCSV(MyArray() As Variant, sFilename As String, Optional sDelimiter As String = ",")

改为

Public Sub SaveAsCSV(MyArray As Variant, sFilename As String, Optional sDelimiter As String = ",")

但是这只会创建一个空白文件,因为这里现在有一个错误。这会触发错误处理。

我想不通的是,当我在监视窗口中观看 MyArray 时,它会按照应有的方式填充,所以我无法弄清楚这个错误。任何帮助表示赞赏

【问题讨论】:

  • 删除()
  • @ScottCraner 这似乎奏效了!谢谢!

标签: arrays excel vba csv


【解决方案1】:

您需要了解VariantArray of Variant 之间的区别
VBA 中的Variant 变量可以保存任何东西,其中包括一个数组。数组始终是数组:

Dim v1 as Variant
v1 = 3                   ' Now v1 holds an Integer
Redim v1(1 to 10)        ' ...and now it holds an array of Variant
v1(1) = 3                ' The first member of v1 now holds an Integer 
v1 = "VBA is a miracle"  ' Now v1 holds a string (and is no longer an array)

Dim v2() as Variant      ' v2 is an array of Variant per declaration
Redim v2(1 to 10)        ' Assign 10 members to v2
v2(1) = 3                ' The first member of v1 now holds an Integer 
v2 = "VBA is a mystery"  ' This is not possible as v2 is an array!
                         ' (Compiler error "Can't assign to an array)

如果您使用参数MyArray() As Variant 声明您的 Sub,您的意思是您的函数需要一个 Array of 变体作为参数。在您的电话 SaveAsCSV arOut, Application.ActiveWorkbook.Path & "\Demo.csv" 中,您将变量 arOut 作为参数传递。
这个变量很可能被声明为Variant(而不是Array of Variant),因此您会得到第一个编译器错误:A variant is not an Array of Variant。编译器根本不知道在运行时,arOut 将是一个数组。它也可以是 Integer 或 String 或其他任何东西。

现在您将例程声明的参数更改为MyArray As Variant,并且您的调用有效,编译器不再抱怨,它假定MyArray 可以是任何东西。如果你给它分配一个数字或字符串,无论如何都会调用Sub(当然它不会工作)。

在例程中,您编写UBound(MyArray(), 1)。编译器再次抱怨,因为 MyArray 不是 一个数组。通过将调用更改为UBound(MyArray, 1),编译器很高兴。如果MyArray 不包含数组,则会出现运行时错误(类型不匹配)。

所以在函数声明中使用MyArray as Variant 并在UBound 中使用它时删除括号可以解决您的问题,每个人都很高兴。

有一点缺点:如前所述,编译器无法保护您不使用无效参数调用 Sub。作为程序员,您希望编译器能够捕获尽可能多的问题。所以另一种方法是将arOut 声明为数组:

Dim arOut() as Variant
arOut = Range("A1:F10")  ' Do whatever magic you need to fill the array.

现在您可以返回声明Public Sub SaveAsCSV(MyArray() As Variant...。并且使用UBound(myArray(), 1) 也可以。但是,无论如何,您都可以(并且应该)写UBound(myArray, 1)

【讨论】:

  • 感谢您的详细解答!我不知道您可以创建一个只能是数组的变量。我认为使用普通的旧变体是唯一的方法。你能解释一下这条线吗? “但是,在任何情况下,您都可以(并且应该)编写 UBound(myArray, 1) 。”如果我给它提供不是数组的东西会引发错误,我不想那样使用 Ubound(myArray(), 1)" 吗?arOut 应该而且只会是一个数组。
  • 由于myArray 已经被声明为数组,因此不会发生“类型不匹配”运行时错误的风险,并且额外的括号只会让语句看起来更复杂(老实说,我只是从您的代码中学习并尝试它是有效的语法,以前从未见过)。
  • 当然,在任何情况下,当您将一维数组作为参数传递并使用UBound(MyArray, 2) 时,您都存在运行时错误“Array out bounds”的风险
猜你喜欢
  • 2013-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-09
  • 1970-01-01
  • 2010-09-27
  • 1970-01-01
相关资源
最近更新 更多