2012-10-25 34 views
3

我以前寫的單元格區域的內容(值)與在VBA中寫命令的文本文件,例如:有沒有辦法將批量範圍寫入文本/ CSV文件?

write #myfile, Range("A1").value, Range("A2).value, Range("A3).value

是否存在一個更優雅和方便的內置-in方法將整個範圍直接轉儲到分隔文件,甚至可能一次覆蓋多行?還是有人提出了一個定製的解決方案?我認爲這會非常有用。

+0

請參閱下面的解決方案。使用變體數組而不是範圍循環對代碼運行時產生巨大影響 – brettdj

回答

4

我給你寫了這一點,仍然可以得到改善,但我認爲這是不夠好:

Sub SaveRangeAsCSV(r As Range, filename As String, overwrite As Boolean) 
    Dim wB As Workbook 
    Dim c As Range 
    Dim usedRows As Long 
    If overwrite Then 
     If Dir(filename) <> "" Then Kill filename 
     If Err.Number <> 0 Then 
      MsgBox "Could not delete previously existing file." & vbNewLine & Err.Number & ": " & Err.Description 
      Exit Sub 
     End If 
    End If 
    If Dir(filename) <> "" Then 
     Set wB = Workbooks.Open(filename) 
    Else 
     Set wB = Workbooks.Add 
    End If 

    With wB.Sheets(1) 
     usedRows = .UsedRange.Rows.Count 
     'Check if more than 1 row is in the used range. 
     If usedRows = 1 Then 
      'Since there's only 1 row, see if there's more than 1 cell. 
      If .UsedRange.Cells.Count = 1 Then 
       'Since there's only 1 cell, check the contents 
       If .Cells(1, 1) = "" Then 
         'you're dealing with a blank workbook 
         usedRows = 0 
       End If 
      End If 
     End If 
     'Check if range is contigious 
     If InStr(r.Address, ",") Then 
      For Each c In r.Cells 
       .Range(c.Address).Offset(usedRows, 0).Value = c.Value 
      Next 
     Else 
      .Range(r.Address).Offset(usedRows, 0).Value = r.Value 
     End If 
    End With 
    wB.SaveAs filename, xlCSV, , , , False 
    wB.Saved = True 
    wB.Close 
End Sub 
Sub Example() 
    'I used Selection here just to make it easier to test. 
    'Substitute your actual range, and actual desired filepath 
    'If you pass false for overwrite, it assumes you want to append 
    'It will give you a pop-up asking if you want to overwrite, which I could avoid 
    'by copying the worksheet and then closing and deleting the file etc... but I 
    'already spent enough time on this one. 
    SaveRangeAsCSV Selection, "C:\proofOfConcept.csv", False 
End Sub 

在使用它,只是提供實際範圍,實際文件名,你是否不希望覆蓋文件。 :)這已更新爲允許非連續範圍。對於合併的單元格,它最終會將該值放入合併範圍的第一個單元格中。

+0

非常友善。看起來不錯。我想知道它是否適用於不連續的範圍?我將需要能夠在文件中追加新的範圍。 wB.SaveAs方法是否允許這樣做?我認爲它只適用於節省「一槍」數據。 – Steve06

+0

你說得對,對於非連續的範圍這將失敗。我正在發佈更新以糾正該問題。 :) –

+0

不錯,但是這個「SaveAs-Method」還允許將新的範圍附加到現有文件的底部嗎?我猜是覆蓋? – Steve06

2

這是我自己想出瞭解決方案,並符合我的需要最好的,據我可以看到:

Sub DumpRangeToTextFile(filehandle As Integer, source As Range) 
Dim row_range As Range, mycell As Range 
For Each row_range In source.rows 
    For Each mycell In row_range.cells 
     Write #filehandle, mycell.Value; 
    Next mycell 
    Write #filehandle, 
Next row_range 
End Sub 

簡短而親切! ;)

儘管如此,我仍然給丹尼爾庫克的解決方案,這也是非常有用的信用它應得的。

+0

輝煌!簡短而甜蜜! – richie

0

從我的文章Creating and Writing to a CSV FIle using Excel VBA

本文提供了兩個VBA代碼示例創建並寫入到CSV文件:

  1. 創建使用開放輸出FreeFile CSV文件。
  2. 使用FileSystemObject對象創建CSV文件。

我更喜歡後一種方法,主要是因爲我正在使用FileSystemObject進行進一步編碼,例如遞歸處理子文件夾中的所有文件(儘管本文中未使用該技術)。

代碼註釋

此代碼必須從一個普通VBA代碼模塊中運行。否則, 代碼將導致錯誤,如果用戶嘗試從給定Const的用法的ThisWorkbook 或Sheet Code窗格運行它。

值得注意的是,ThisWorkbook和Sheet代碼部分 應該只保留用於事件編碼,「標準」VBA應該從標準代碼模塊運行 。

請注意,出於示例代碼的目的, CSV輸出文件的文件路徑是「硬編碼」的: C:\ test \ myfile.csv位於代碼的頂部。您可能希望以編程方式設置輸出文件,例如作爲 函數參數。

如前所述;出於示例目的,此代碼TRANSPOSES COLUMNS AND ROWS;也就是說,輸出文件包含一個CSV行,用於 所選範圍中的每列。通常情況下,CSV輸出將逐行顯示爲 ,回顯屏幕上可見的佈局,但我想 表明通過使用VBA代碼生成輸出提供了 選項,例如,使用Save 作爲... CSV文本菜單選項。

代碼

Const sFilePath = "C:\test\myfile.csv" 
Const strDelim = "," 

'Option 1 
Sub CreateCSV_Output() 
Dim ws As Worksheet 
Dim rng1 As Range 
Dim X 
Dim lRow As Long 
Dim lCol As Long 
Dim strTmp As String 
Dim lFnum As Long 

lFnum = FreeFile 
Open sFilePath For Output As lFnum 

For Each ws In ActiveWorkbook.Worksheets 
    'test that sheet has been used 
    Set rng1 = ws.UsedRange 
    If Not rng1 Is Nothing Then 
     'only multi-cell ranges can be written to a 2D array 
     If rng1.Cells.Count > 1 Then 
      X = ws.UsedRange.Value2 
      'The code TRANSPOSES COLUMNS AND ROWS by writing strings column by column 
      For lCol = 1 To UBound(X, 2) 
       'write initial value outside the loop 
       strTmp = IIf(InStr(X(1, lCol), strDelim) > 0, """" & X(1, lCol) & """", X(1, lCol)) 
       For lRow = 2 To UBound(X, 1) 
        'concatenate long string & (short string with short string) 
        strTmp = strTmp & (strDelim & IIf(InStr(X(lRow, lCol), strDelim) > 0, """" & X(lRow, lCol) & """", X(lRow, lCol))) 
       Next lRow 
       'write each line to CSV 
       Print #lFnum, strTmp 
      Next lCol 
     Else 
      Print #lFnum, IIf(InStr(ws.UsedRange.Value, strDelim) > 0, """" & ws.UsedRange.Value & """", ws.UsedRange.Value) 
     End If 
    End If 
Next ws 

Close lFnum 
MsgBox "Done!", vbOKOnly 

End Sub 

'Option 2 
Sub CreateCSV_FSO() 
Dim objFSO 
Dim objTF 
Dim ws As Worksheet 
Dim lRow As Long 
Dim lCol As Long 
Dim strTmp As String 
Dim lFnum As Long 

Set objFSO = CreateObject("scripting.filesystemobject") 
Set objTF = objFSO.createtextfile(sFilePath, True, False) 

For Each ws In ActiveWorkbook.Worksheets 
    'test that sheet has been used 
    Set rng1 = ws.UsedRange 
    If Not rng1 Is Nothing Then 
     'only multi-cell ranges can be written to a 2D array 
     If rng1.Cells.Count > 1 Then 
      X = ws.UsedRange.Value2 
      'The code TRANSPOSES COLUMNS AND ROWS by writing strings column by column 
      For lCol = 1 To UBound(X, 2) 
       'write initial value outside the loop 
       strTmp = IIf(InStr(X(1, lCol), strDelim) > 0, """" & X(1, lCol) & """", X(1, lCol)) 
       For lRow = 2 To UBound(X, 1) 
        'concatenate long string & (short string with short string) 
        strTmp = strTmp & (strDelim & IIf(InStr(X(lRow, lCol), strDelim) > 0, """" & X(lRow, lCol) & """", X(lRow, lCol))) 
       Next lRow 
       'write each line to CSV 
       objTF.writeline strTmp 
      Next lCol 
     Else 
      objTF.writeline IIf(InStr(ws.UsedRange.Value, strDelim) > 0, """" & ws.UsedRange.Value & """", ws.UsedRange.Value) 
     End If 
    End If 
Next ws 

objTF.Close 
Set objFSO = Nothing 
MsgBox "Done!", vbOKOnly 

End Sub 
0

這些方法上方橫跨單元格區域迭代以導出數據。由於所有的錯誤檢查,任何通過循環遍歷表格中一系列單元格的操作都非常緩慢。

這是我沒有迭代的方法。基本上,它使用內置函數「Join()」來完成繁重的工作,這將是您的迭代循環。這要快得多。

的相關閱讀()子程序我在另一個帖子詳細介紹:https://stackoverflow.com/a/35688988/2800701

這是寫()子程序(注:這是假定你的文字是預格式化工作表中的正確規範然後再導出它;它只能在單列上工作...不在多列範圍內):

Public Sub WriteRangeAsPlainText(ExportRange As Range, Optional textfilename As Variant) 
    If IsMissing(textfilename) Then textfilename = Application.GetSaveAsFilename(FileFilter:="Text Files (*.txt), *.txt") 
    If textfilename = "" Then Exit Sub 

    Dim filenumber As Integer 
    filenumber = FreeFile 
    Open textfilename For Output As filenumber 

    Dim textlines() As Variant, outputvar As Variant 

    textlines = Application.Transpose(ExportRange.Value) 
    outputvar = Join(textlines, vbCrLf) 
    Print #filenumber, outputvar 
    Close filenumber 
End Sub 
相關問題