【问题标题】:Macro to convert .xls to .xlsx crashes Excel将 .xls 转换为 .xlsx 的宏使 Excel 崩溃
【发布时间】:2016-11-29 03:24:59
【问题描述】:

我的目标是将包含 .xls 文件的目录转换为 .xlsx 文件,同时保留嵌入图像。因为预期的文件集有数百个,所以需要一个自动化的解决方案。我的测试集有 532 个 .xls 文件。一次打开一个文件并保存它们确实有效,但显然很乏味,我更喜欢自动化。

为此,我尝试使用 Office 文件转换器,它告诉我无法转换任何文件。微软干杯。

我也尝试了几个宏建议。他们似乎都以:

“Microsoft Excel 已停止工作”

我无法确定它崩溃的原因(帮助在哪里寻找有用的日志会很棒,EventViewer 似乎不包含任何对我有直接价值的东西)。起初我以为它正在打开文件,然后我读到它可能正在关闭文件。 (似乎其他人也经历过)。

使用 xlRepairData 运行打开似乎没有什么不同。

Set wbk = Workbooks.Open(Filename:=strPath & strFile, CorruptLoad:=xlRepairData)

xlExtractData 运行良好,但也去除了图像,而不是所需的行为!

Set wbk = Workbooks.Open(Filename:=strPath & strFile, CorruptLoad:=xlExtractData)

然后,我创建了一批全新的 .xls 文件,其中包含一只兔子和小猫的图片,并复制了它,直到我拥有超过 50 个文件。运行这个测试集重复打开和关闭就好了。 啊-哈哈!

我现在的印象是我试图打开的文件导致了问题。我特别缩小了一个范围,我可以在“受保护的视图”中手动打开它,因为 Excel 认为它非常可疑。不幸的是,任何尝试打开它的宏都会导致

“Microsoft Excel 已停止工作”

我最近看到了很多。

很遗憾,我无法共享特定文件,因为它包含我不允许共享的数据,并且重新保存文件以去除私人数据可能会消除错误情况。 (关于如何在新文件中重新创建条件的建议也会很有用)。

我已尝试修改 here 找到的两个建议解决方案。 Excel 崩溃。也偶尔会显示这个运行时错误:

“运行时错误 '-2147021892 (80070bbc)': Office 检测到 这个文件有问题。为了帮助保护您的计算机,此文件不能 被打开。”

我尝试在检测到错误时跳过文件,这也以灾难告终 - Excel 崩溃。是否有正确的方法来中止导致错误的 .Open 操作?

Sub ConvertToXlsx()
    Dim strPath As String
    Dim strFile As String
    Dim wbk As Workbook

    strPath = "C:\Test1\"
    strFile = Dir(strPath & "*.xls")
    On Error GoTo NextFile:
    Do While strFile <> ""
        If Right(strFile, 3) = "xls" Then
            Set wbk = Workbooks.Open(Filename:=strPath & strFile)
            'Save would go here
            wbk.Close SaveChanges:=False
            'Deleting the .xls file after would be a nice touch
        End If
NextFile:
        strFile = Dir
    Loop
End Sub

我不确定如何有效地使用this solution

 Application.ProtectedViewWindows.Open Filename:=fName
 Application.ActiveProtectedViewWindow.Edit

是否有一段代码可以通过目录运行并打开 any .xls 文件?它应该优雅地处理错误,而不是完全崩溃 Excel。也许它能够在尝试 .Open 之前检查文件的兼容性? Excel 只是适合这项工作的错误工具吗?

快速配置信息:
Windows 8.1 专业版 - Excel 2013
Windows 10 - Excel 2013

在此先感谢您提供任何理智的帮助。 :)


我的解决方法:

我安装了 LibreOffice 5 并从命令行运行它。
{install_dir}\program\soffice --headless --convert-to xlsx:"Calc MS Excel 2007 XML" {filename}.xls 这要么有效,并创建 xlsx 文件,要么失败......静默。 我使用下面的 windows 批处理脚本来遍历 xls 文件的文件夹。

@echo off

set soffice="C:\Program Files\LibreOffice 5\program\soffice"
for %%v in (*.xls) do (
    %soffice% --headless --convert-to xlsx:"Calc MS Excel 2007 XML" "%%v"
    if not exist "%%~nv.xlsx" (
        echo "ERROR: %%~nv"
    ) else (
        echo "***deleting %%v"
        del "%%v"
    )
)

脚本完成后,有 214 个文件不会被 LibreOffice 转换,通过 Excel 宏打开这些文件似乎没有问题(我通过运行上面的打开->关闭代码进行了测试)。所以现在提出的解决方案和我一直试图适应的任何解决方案都应该有效。确认后会更新。

【问题讨论】:

  • 我认为这与文件的处理方式无关,因为我在打开和关闭大量文件后遇到 Excel 随机崩溃的类似经历。当 Excel 应用程序崩溃时,我不得不制作单独的 VB.Net 程序来重新启动进程。
  • 您要转换的文件是原生 xls 文件吗?文件的来源是什么?它们是否有任何机会将 HTML 文件伪装成 xls 文件?
  • @TimWilliams 他们以 xls 文件的形式开始了生活,其中带有锁定的工作表,特定单元格未锁定,创建了一个标准表单,应该很容易在其上运行宏。它们被分发以收集数据,由许多不同的人在不同的机器上使用不同版本的 Excel 进行编辑,然后发回。我检查了您对 HTML 文件的预感(它们不是),并发现一个有趣的字符串隐藏在一个问题文件中。 “微软麦金塔 Excel”。这只有在使用 Notepad++ 中的编码菜单后才可见。
  • @Slai 不太令人鼓舞,但感谢您采用的解决方法。
  • @dabell 在好的方面,管理 Excel 应用程序的程序可以在处理之前将每个文件移动到不同的文件夹,以便它可以同时在多台机器上运行(甚至几个实例如果他们使用不同的 Excel 应用程序实例,则使用同一台机器)

标签: vba excel excel-2013 xlsm


【解决方案1】:

好的;所以以下内容可能对您有用。如前所述,文件在保存后将被删除。结果 - 如果它确实出错,希望您只需要再次运行宏(或处理产生错误的文件 - 这应该是文件夹中的第一个 (*.xls) 文件)

Sub ConvertXLStoXLSX()
    Dim sFolder As String: sFolder = "P:\Test"
    Dim wbOpen As Workbook, sFullName As String

    On Error GoTo ExitSub
    Application.ScreenUpdating = False
    For Each Item In EnumerateFiles(sFolder)
        sFullName = sFolder & "\\" & Item
        Set wbOpen = GetWorkBook(sFullName)
        Debug.Print wbOpen.Name
        Application.DisplayAlerts = False
            On Error Resume Next
                wbOpen.SaveAs FileName:=sFullName & "x", FileFormat:=xlOpenXMLWorkbook
                wbOpen.Close False
            On Error GoTo ExitSub
            If Len(Dir$(sFullName & "x")) > 0 Then Kill (sFullName)
        Application.DisplayAlerts = True
    Next Item

ExitSub:
    Application.ScreenUpdating = True
    Application.DisplayAlerts = True
End Sub

Function EnumerateFiles(sFolder As String) As Variant
    Dim objFSO As Object: Set objFSO = CreateObject("Scripting.FileSystemObject")
    Dim objFolder As Object: Set objFolder = objFSO.GetFolder(sFolder)
    Dim objFile As Object, V() As String

    For Each objFile In objFolder.Files
        If Right(objFile.Name, 4) = ".xls" Then
            If IsArrayAllocated(V) = False Then
                ReDim V(0)
            Else
                ReDim Preserve V(UBound(V) + 1)
            End If
            V(UBound(V)) = objFile.Name
        End If
    Next objFile

    EnumerateFiles = V
End Function

Function IsArrayAllocated(Arr As Variant) As Boolean
    On Error Resume Next
    IsArrayAllocated = IsArray(Arr) And Not IsError(LBound(Arr, 1)) And LBound(Arr, 1) <= UBound(Arr, 1)
End Function

Public Function GetWorkBook(ByVal sFullName As String, Optional ReadOnly As Boolean) As Workbook
    Dim sFile As String: sFile = Dir(sFullName)
    On Error Resume Next
        Set GetWorkBook = Workbooks(sFile)
        If GetWorkBook Is Nothing Then Set GetWorkBook = Workbooks.Open(sFullName, ReadOnly:=ReadOnly)
        If GetWorkBook Is Nothing Then
            Dim wbPVW As ProtectedViewWindow
            Set wbPVW = Application.ProtectedViewWindows.Open(sFullName).Edit
            Set GetWorkBook = wbPVW.Workbook
        End If
    On Error GoTo 0
End Function

【讨论】:

  • 这是一个有趣的解决方案。当它不使 Excel 崩溃时(如我之前所见),它会挂起并打开其中一个工作簿。不过,单步执行似乎会使它更可重复地崩溃。我会再做一些测试来看看发生了什么。
  • 可能与受保护的视图窗口有关。我没有任何文件可以测试该代码 - 所以它没有优化。附带说明;您可以在高级信任中心设置中关闭受保护的视图,这样可以解决问题吗?
  • 关闭受保护的视图似乎没有什么不同。
猜你喜欢
  • 2013-01-25
  • 1970-01-01
  • 2016-07-11
  • 2012-09-06
  • 2011-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-29
相关资源
最近更新 更多