【问题标题】:Saving Excel data as csv with VBA - removing blank rows at end of file to save使用 VBA 将 Excel 数据保存为 csv - 删除文件末尾的空白行以保存
【发布时间】:2012-07-12 07:20:40
【问题描述】:

我正在 VBA 中创建一组 csv 文件。

我的脚本正在创建我需要的数据集,但循环的多次迭代中的行数不同。例如,对于 i=2,我有 100,000 行,但对于 i=3,我有 22,000 行。问题是当 Excel 保存这些单独的 csv 文件时,它不会在末尾截断空间。这会在文件末尾留下 78,000 个空白行,这是一个问题,因为我需要生成大约 2,000 个文件,每个文件都有几兆字节大。 (我在 SQL 中有一些我需要的数据,但无法在 SQL 本身中进行数学运算。长话短说。)

此问题通常在手动保存时发生 - 您需要在删除行后关闭文件,然后重新打开,在这种情况下这不是一个选项,因为它在 VBA 中自动发生。使用另一种语言的脚本保存后删除空白行并不是一个真正的选择,因为我实际上需要输出文件以适合可用的驱动器,而且它们现在不必要地巨大。

我试过Sheets(1).Range("A2:F1000001").ClearContents,但这不会截断任何内容。在保存之前删除行应该同样没有效果,因为 Excel 将所有行保存到文件末尾,因为它存储了操作的最右下角的单元格。有没有办法让excel只保存我需要的行?

这是我用来保存的代码:(截断发生在前面,在调用这个的路由中)

Sub SaveCSV()
'Save the file as a CSV...
  Dim OutputFile As Variant
  Dim FilePath As Variant

  OutputPath = ActiveWorkbook.Worksheets("Macro").Range("B2").Value
  OutputFile = OutputPath & ActiveWorkbook.Worksheets("Macro").Range("B1").Value
  Application.DisplayAlerts = False 'DISABLE ALERT on Save - overwrite, etc.
  ActiveWorkbook.SaveAs Filename:=OutputFile, FileFormat:=xlCSV, CreateBackup:=False
  Application.DisplayAlerts = True 'DISPLAY ALERTS
End Sub

相关的代码在这里:

'While looping through Al, inside of looping through A and B...
'Created output values needed in this case, in an array...

Sheets(1).Range("A2:E90001") = Output

ActiveWorkbook.Worksheets(1).Range("F2").Formula = "=(does not matter, some formula)"
ActiveWorkbook.Worksheets(1).Range("F2").AutoFill Destination:=Range("F2:F90001")

'Set Filename to save into...
ActiveWorkbook.Worksheets("Macro").Range("B1").Value = "Values_AP" & Format(A, "#") & "_BP" & Format(B, "#") & "_Al" & Format(Al, "#")

'Save Sheet and reset...
Call SaveCSV
Sheets(1).Range("A2:F90001").ClearContents
CurrRow = 1

Next Al

【问题讨论】:

  • 我添加了一段调用保存例程的代码。它是我无法真正在线共享的系统的一部分,而且使用的数百行代码与问题无关。当然,如果有某种方法可以完成任务,所有这些都应该是无关紧要的——我不只是想要“固定”代码作为解决方案,我想知道如何做到这一点。

标签: excel csv vba


【解决方案1】:

您可以让UsedRange 重新计算自己,而无需使用简单的删除列和行

ActiveSheet.UsedRange

或者,您可以通过使用DRJ's VBAexpress article 等代码删除最后使用的单元格下方的区域,或使用ASAP Utilities 等插件来自动手动删除“false”usedrange

DRJ 文章中的功能是;

Option Explicit 

Sub ExcelDiet() 

Dim j               As Long 
Dim k               As Long 
Dim LastRow         As Long 
Dim LastCol         As Long 
Dim ColFormula      As Range 
Dim RowFormula      As Range 
Dim ColValue        As Range 
Dim RowValue        As Range 
Dim Shp             As Shape 
Dim ws              As Worksheet 

Application.ScreenUpdating = False 
Application.DisplayAlerts = False 

On Error Resume Next 

For Each ws In Worksheets 
    With ws 
         'Find the last used cell with a formula and value
         'Search by Columns and Rows
        On Error Resume Next 
        Set ColFormula = .Cells.Find(What:="*", After:=Range("A1"), LookIn:=xlFormulas, _ 
        LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious) 
        Set ColValue = .Cells.Find(What:="*", After:=Range("A1"), LookIn:=xlValues, _ 
        LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious) 
        Set RowFormula = .Cells.Find(What:="*", After:=Range("A1"), LookIn:=xlFormulas, _ 
        LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious) 
        Set RowValue = .Cells.Find(What:="*", After:=Range("A1"), LookIn:=xlValues, _ 
        LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious) 
        On Error GoTo 0 

         'Determine the last column
        If ColFormula Is Nothing Then 
            LastCol = 0 
        Else 
            LastCol = ColFormula.Column 
        End If 
        If Not ColValue Is Nothing Then 
            LastCol = Application.WorksheetFunction.Max(LastCol, ColValue.Column) 
        End If 

         'Determine the last row
        If RowFormula Is Nothing Then 
            LastRow = 0 
        Else 
            LastRow = RowFormula.Row 
        End If 
        If Not RowValue Is Nothing Then 
            LastRow = Application.WorksheetFunction.Max(LastRow, RowValue.Row) 
        End If 

         'Determine if any shapes are beyond the last row and last column
        For Each Shp In .Shapes 
            j = 0 
            k = 0 
            On Error Resume Next 
            j = Shp.TopLeftCell.Row 
            k = Shp.TopLeftCell.Column 
            On Error GoTo 0 
            If j > 0 And k > 0 Then 
                Do Until .Cells(j, k).Top > Shp.Top + Shp.Height 
                    j = j + 1 
                Loop 
                If j > LastRow Then 
                    LastRow = j 
                End If 
                Do Until .Cells(j, k).Left > Shp.Left + Shp.Width 
                    k = k + 1 
                Loop 
                If k > LastCol Then 
                    LastCol = k 
                End If 
            End If 
        Next 

        .Range(.Cells(1, LastCol + 1), .Cells(.Rows.Count, .Columns.Count)).EntireColumn.Delete 
        .Range("A" & LastRow + 1 & ":A" & .Rows.Count).EntireRow.Delete 
    End With 
Next 

Application.ScreenUpdating = True 
Application.DisplayAlerts = True 

End Sub 

【讨论】:

    【解决方案2】:

    Excel 保存UsedRange。为了截断UsedRange,您需要删除整行并保存文件。

    如果这不是一个选项,请插入一个新工作表,将准备好的数据复制到其中(从而使其UsedRange 与实际数据匹配),使用Worksheet.SaveAs(而不是Workbook.SaveAs)并删除工作表。

    虽然这里的实际问题是为什么你的 UsedRange 首先会变得那么大。

    【讨论】:

    • 感谢您的建议。我无法保存文件而不将其另存为 - 当前文件名是一个 csv,它会覆盖以前的文件。 Usedrange 会有所不同,因为在循环中,一些项目有多达 1m 行的输出,而循环中的后续项目则少得多。我将尝试插入一个新工作表以保存该工作表,然后将其删除 - 但我担心这会极大地减慢宏。
    • @DavidManheim您也可以尝试将原始文件作为xls文件保存到系统临时文件夹中,截断使用的范围,然后立即将其再次保存为csv。
    • 这可能是一个更好的解决方案。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-26
    • 2020-12-06
    • 2016-07-27
    相关资源
    最近更新 更多