【问题标题】:Save each sheet in a workbook to separate CSV files将工作簿中的每张工作表保存为单独的 CSV 文件
【发布时间】:2008-09-12 14:04:02
【问题描述】:

如何保存 Excel 工作簿中的每张工作表,以使用宏分隔 CSV 文件?

我有一个包含多张工作表的 Excel,我正在寻找一个可以将每张工作表保存到单独的 CSV (comma separated file) 的宏。 Excel 不允许您将所有工作表保存到不同的 CSV 文件中。

【问题讨论】:

    标签: excel vba csv


    【解决方案1】:

    @AlexDuggleby:你不需要复制工作表,你可以直接保存它们。例如:

    Public Sub SaveWorksheetsAsCsv()
    Dim WS As Excel.Worksheet
    Dim SaveToDirectory As String
    
        SaveToDirectory = "C:\"
    
        For Each WS In ThisWorkbook.Worksheets
            WS.SaveAs SaveToDirectory & WS.Name, xlCSV
        Next
    
    End Sub
    

    唯一潜在的问题是您的工作簿保存为最后一个 csv 文件。如果您需要保留原始工作簿,则需要另存为。

    【讨论】:

    • +1 要在Excel中使用,可以:Alt+F11,插入>模块,粘贴代码,点击播放按钮。
    • 另一个问题,如果保存在您的个人工作簿中,则不起作用。否则很棒!
    • @bishop 如何运行这段代码?我将它粘贴到 MAC 上 Excel 2016 的 VBA 编辑器中,但无法运行。我收到此错误运行时错误“1004”:应用程序定义或对象定义错误
    • 如果您更改 SaveToDirectory,请确保保留尾部反斜杠。
    • 谢谢!请注意:我注意到如果有 .在工作表的名称中,不会将 .CSV 扩展名添加到文件名中。
    【解决方案2】:

    这是一个可以为您提供可视文件选择器来选择要将文件保存到的文件夹,还可以让您选择 CSV 分隔符(我使用管道“|”,因为我的字段包含逗号而我不想处理引号):

    ' ---------------------- Directory Choosing Helper Functions -----------------------
    ' Excel and VBA do not provide any convenient directory chooser or file chooser
    ' dialogs, but these functions will provide a reference to a system DLL
    ' with the necessary capabilities
    Private Type BROWSEINFO    ' used by the function GetFolderName
        hOwner As Long
        pidlRoot As Long
        pszDisplayName As String
        lpszTitle As String
        ulFlags As Long
        lpfn As Long
        lParam As Long
        iImage As Long
    End Type
    
    Private Declare Function SHGetPathFromIDList Lib "shell32.dll" _
                                                 Alias "SHGetPathFromIDListA" (ByVal pidl As Long, ByVal pszPath As String) As Long
    Private Declare Function SHBrowseForFolder Lib "shell32.dll" _
                                               Alias "SHBrowseForFolderA" (lpBrowseInfo As BROWSEINFO) As Long
    
    Function GetFolderName(Msg As String) As String
        ' returns the name of the folder selected by the user
        Dim bInfo As BROWSEINFO, path As String, r As Long
        Dim X As Long, pos As Integer
        bInfo.pidlRoot = 0&    ' Root folder = Desktop
        If IsMissing(Msg) Then
            bInfo.lpszTitle = "Select a folder."
            ' the dialog title
        Else
            bInfo.lpszTitle = Msg    ' the dialog title
        End If
        bInfo.ulFlags = &H1    ' Type of directory to return
        X = SHBrowseForFolder(bInfo)    ' display the dialog
        ' Parse the result
        path = Space$(512)
        r = SHGetPathFromIDList(ByVal X, ByVal path)
        If r Then
            pos = InStr(path, Chr$(0))
            GetFolderName = Left(path, pos - 1)
        Else
            GetFolderName = ""
        End If
    End Function
    '---------------------- END Directory Chooser Helper Functions ----------------------
    
    Public Sub DoTheExport()
        Dim FName As Variant
        Dim Sep As String
        Dim wsSheet As Worksheet
        Dim nFileNum As Integer
        Dim csvPath As String
    
    
        Sep = InputBox("Enter a single delimiter character (e.g., comma or semi-colon)", _
                       "Export To Text File")
        'csvPath = InputBox("Enter the full path to export CSV files to: ")
    
        csvPath = GetFolderName("Choose the folder to export CSV files to:")
        If csvPath = "" Then
            MsgBox ("You didn't choose an export directory. Nothing will be exported.")
            Exit Sub
        End If
    
        For Each wsSheet In Worksheets
            wsSheet.Activate
            nFileNum = FreeFile
            Open csvPath & "\" & _
                 wsSheet.Name & ".csv" For Output As #nFileNum
            ExportToTextFile CStr(nFileNum), Sep, False
            Close nFileNum
        Next wsSheet
    
    End Sub
    
    
    
    Public Sub ExportToTextFile(nFileNum As Integer, _
                                Sep As String, SelectionOnly As Boolean)
    
        Dim WholeLine As String
        Dim RowNdx As Long
        Dim ColNdx As Integer
        Dim StartRow As Long
        Dim EndRow As Long
        Dim StartCol As Integer
        Dim EndCol As Integer
        Dim CellValue As String
    
        Application.ScreenUpdating = False
        On Error GoTo EndMacro:
    
        If SelectionOnly = True Then
            With Selection
                StartRow = .Cells(1).Row
                StartCol = .Cells(1).Column
                EndRow = .Cells(.Cells.Count).Row
                EndCol = .Cells(.Cells.Count).Column
            End With
        Else
            With ActiveSheet.UsedRange
                StartRow = .Cells(1).Row
                StartCol = .Cells(1).Column
                EndRow = .Cells(.Cells.Count).Row
                EndCol = .Cells(.Cells.Count).Column
            End With
        End If
    
        For RowNdx = StartRow To EndRow
            WholeLine = ""
            For ColNdx = StartCol To EndCol
                If Cells(RowNdx, ColNdx).Value = "" Then
                    CellValue = ""
                Else
                    CellValue = Cells(RowNdx, ColNdx).Value
                End If
                WholeLine = WholeLine & CellValue & Sep
            Next ColNdx
            WholeLine = Left(WholeLine, Len(WholeLine) - Len(Sep))
            Print #nFileNum, WholeLine
        Next RowNdx
    
    EndMacro:
        On Error GoTo 0
        Application.ScreenUpdating = True
    
    End Sub
    

    【讨论】:

    • 由于问题没有要求使用非标准分隔符,我不清楚您为什么要逐个单元格地编写例程。如果您要沿着这条路线使用变体数组而不是范围,请在引用它之前重新计算UsedRange(删除潜在的多余空间),将长字符串与组合短字符串WholeLine = WholeLine & (CellValue & Sep)连接起来,使用字符串函数而不是变体(@987654324 @不是Left)等
    【解决方案3】:

    这是我的解决方案应该适用于 Excel > 2000,但仅在 2007 年进行了测试:

    Private Sub SaveAllSheetsAsCSV()
    On Error GoTo Heaven
    
    ' each sheet reference
    Dim Sheet As Worksheet
    ' path to output to
    Dim OutputPath As String
    ' name of each csv
    Dim OutputFile As String
    
    Application.ScreenUpdating = False
    Application.DisplayAlerts = False
    Application.EnableEvents = False
    
    ' ask the user where to save
    OutputPath = InputBox("Enter a directory to save to", "Save to directory", Path)
    
    If OutputPath <> "" Then
    
        ' save for each sheet
        For Each Sheet In Sheets
    
            OutputFile = OutputPath & "\" & Sheet.Name & ".csv"
    
            ' make a copy to create a new book with this sheet
            ' otherwise you will always only get the first sheet
            Sheet.Copy
            ' this copy will now become active
            ActiveWorkbook.SaveAs FileName:=OutputFile, FileFormat:=xlCSV, CreateBackup:=False
            ActiveWorkbook.Close
        Next
    
    End If
    
    Finally:
    Application.ScreenUpdating = True
    Application.DisplayAlerts = True
    Application.EnableEvents = True
    
    Exit Sub
    
    Heaven:
    MsgBox "Couldn't save all sheets to CSV." & vbCrLf & _
            "Source: " & Err.Source & " " & vbCrLf & _
            "Number: " & Err.Number & " " & vbCrLf & _
            "Description: " & Err.Description & " " & vbCrLf
    
    GoTo Finally
    End Sub
    

    (OT:我想知道 SO 是否会取代我的一些小博客)

    【讨论】:

    • 谢谢!在 Office 2010 中工作。我花了一段时间才意识到必须去掉文件路径中的尾随“/”,否则会出错
    【解决方案4】:

    基于 Graham 的回答,额外的代码将工作簿以原始格式保存回其原始位置。

    Public Sub SaveWorksheetsAsCsv()
    
    Dim WS As Excel.Worksheet
    Dim SaveToDirectory As String
    
    Dim CurrentWorkbook As String
    Dim CurrentFormat As Long
    
     CurrentWorkbook = ThisWorkbook.FullName
     CurrentFormat = ThisWorkbook.FileFormat
    ' Store current details for the workbook
    
          SaveToDirectory = "C:\"
    
          For Each WS In ThisWorkbook.Worksheets
              WS.SaveAs SaveToDirectory & WS.Name, xlCSV
          Next
    
     Application.DisplayAlerts = False
      ThisWorkbook.SaveAs Filename:=CurrentWorkbook, FileFormat:=CurrentFormat
     Application.DisplayAlerts = True
    ' Temporarily turn alerts off to prevent the user being prompted
    '  about overwriting the original file.
    
    End Sub
    

    【讨论】:

    • 抱歉,为什么需要保存原始工作簿?您可以直接关闭它而不进行更改,不是吗?然后您之前也创建了所有 .csv 文件。
    • 你是对的,你不必这样做。这取决于您的工作流程。保存是恢复当前工作簿名称和格式。然后将其保持打开状态以供用户交互。如果没有这样做,那么当用户尝试保存它时,名称将是最后处理的工作表的名称和 .csv 格式。如果您不再需要工作簿,那么 ThisWorkbook.Close SaveChanges:=False 也可以正常工作
    • 我明白了,这就是你想要的 :)
    【解决方案5】:

    to answer from Alex 的一个小修改是开启和关闭自动计算。

    令人惊讶的是,未修改的代码在 VLOOKUP 上运行良好,但在 OFFSET 上却失败了。关闭自动计算也会大大加快保存速度。

    Public Sub SaveAllSheetsAsCSV()
    On Error GoTo Heaven
    
    ' each sheet reference
    Dim Sheet As Worksheet
    ' path to output to
    Dim OutputPath As String
    ' name of each csv
    Dim OutputFile As String
    
    Application.ScreenUpdating = False
    Application.DisplayAlerts = False
    Application.EnableEvents = False
    
    ' Save the file in current director
    OutputPath = ThisWorkbook.Path
    
    
    If OutputPath <> "" Then
    Application.Calculation = xlCalculationManual
    
    ' save for each sheet
    For Each Sheet In Sheets
    
        OutputFile = OutputPath & Application.PathSeparator & Sheet.Name & ".csv"
    
        ' make a copy to create a new book with this sheet
        ' otherwise you will always only get the first sheet
    
        Sheet.Copy
        ' this copy will now become active
         ActiveWorkbook.SaveAs Filename:=OutputFile, FileFormat:=xlCSV,     CreateBackup:=False
        ActiveWorkbook.Close
    Next
    
    Application.Calculation = xlCalculationAutomatic
    
    End If
    
    Finally:
    Application.ScreenUpdating = True
    Application.DisplayAlerts = True
    Application.EnableEvents = True
    
    Exit Sub
    
    Heaven:
    MsgBox "Couldn't save all sheets to CSV." & vbCrLf & _
            "Source: " & Err.Source & " " & vbCrLf & _
            "Number: " & Err.Number & " " & vbCrLf & _
            "Description: " & Err.Description & " " & vbCrLf
    
    GoTo Finally
    End Sub
    

    【讨论】:

    • ActiveWorkbook.SaveAs Filename:=OutputFile, FileFormat:=xlCSV, CreateBackup:=False, Local:=True 将使用本地格式保存日期
    【解决方案6】:

    对于像我这样的 Mac 用户,有几个问题:

    您无法保存到您想要的任何目录。只有少数人可以接收您保存的文件。更多信息there

    这是一个工作脚本,您可以在 Mac 的 Excel 中复制粘贴:

    Public Sub SaveWorksheetsAsCsv()
    
     Dim WS As Excel.Worksheet
     Dim SaveToDirectory As String
    
     SaveToDirectory = "~/Library/Containers/com.microsoft.Excel/Data/"
    
     For Each WS In ThisWorkbook.Worksheet
        WS.SaveAs SaveToDirectory & WS.Name & ".csv", xlCSV
     Next
    
    End Sub
    
    

    【讨论】:

    • +1 用于 Mac。两件事:1. for 循环行缺少 s -- 应该是 ...ThisWorkbook.Worksheet*s* 2. 我收到 '[sheetname].csv' cannot be accessed 错误。然而奇怪的是,如果我将路径设置为SaveToDirectory = './',所有工作表都会成功导出到~/Library/Containers/com.microsoft.Excel/Data/ 文件夹。
    【解决方案7】:

    使用 Visual Basic 循环工作表并保存 .csv 文件。

    1. 在 Excel 中打开 .xlsx 文件。

    2. 选项+F11

    3. InsertModule

    4. 将其插入到模块代码中:

      Public Sub SaveWorksheetsAsCsv()
      
       Dim WS As Excel.Worksheet
       Dim SaveToDirectory As String
      
       SaveToDirectory = "./"
      
       For Each WS In ThisWorkbook.Worksheets
          WS.SaveAs SaveToDirectory & WS.Name & ".csv", xlCSV
       Next
      
      End Sub
      
    5. 运行模块。

      (即点击顶部的播放按钮,然后在弹出的对话框中点击“运行”。)

    6. ~/Library/Containers/com.microsoft.Excel/Data 中找到您的.csv 文件。

      open ~/Library/Containers/com.microsoft.Excel/Data
      
    7. 关闭.xlsx文件。

    8. 冲洗并重复其他.xlsx 文件。

    【讨论】:

      【解决方案8】:

      请查看Von Pookie's answer,所有功劳归于他/她。

       Sub asdf()
      Dim ws As Worksheet, newWb As Workbook
      
      Application.ScreenUpdating = False
      For Each ws In Sheets(Array("EID Upload", "Wages with Locals Upload", "Wages without Local Upload"))
         ws.Copy
         Set newWb = ActiveWorkbook
         With newWb
            .SaveAs ws.Name, xlCSV
            .Close (False)
         End With
      Next ws
      Application.ScreenUpdating = True
      
      End Sub
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-16
        • 1970-01-01
        • 1970-01-01
        • 2016-03-13
        • 2010-09-18
        • 1970-01-01
        相关资源
        最近更新 更多