簡體   English   中英

無法重命名 excel 文件

[英]Cannot rename excel file

Imports System
Imports System.IO
Imports Microsoft.VisualBasic.FileIO
Imports Microsoft.Office.Interop
Module Program
    Dim oxl As Excel.Application
    Dim owbs As Excel.Workbooks
    Dim owb As Excel.Workbook
    Dim osheets As Excel.Worksheets
    Dim osheet As Excel.Worksheet
    Dim owr As Excel.Range

    Dim tempName As String

    Sub Main()
        oxl = CreateObject("Excel.Application")
        oxl.Visible = False
        Dim path As String = "G:\Matthews Asia\Matthews Raw Data"
        Dim names As String() = Directory.GetFiles(path, "*.xlsx")
        Dim newDetails(,) As Object

        'Get the new names and the boundaries of the data set
        newDetails = getNewNames(names)

        'Printing the detials to check getNewNames works or not - works fine
        printNewDetails(newDetails) 'Working fine

        'Rename files
        rename(names, newDetails)

        Console.ReadLine()
    End Sub

    Function getNewNames(ByVal names() As String) As Object(,)
        'Declare Object type array to be returned with the details
        Dim newDetails(names.Length - 1, 2) As Object
        Dim lastRow, lastColumn As Integer

        For i =0 To names.GetUpperBound(0)
            'point to the excel file
            owb = CType(oxl.Workbooks.Open(names(i)), Excel.Workbook) 'Sometimes error comes here
            osheet = CType(owb.Worksheets("Holdings"), Excel.Worksheet)
            owr = CType(osheet.Range("A7"), Excel.Range)

            'Pick new name of file and add the excel extension
            tempName = CStr(owr.Value) & ".xlsx"

            'row & column number of last data point in the dataset
            lastColumn = CType(osheet.Range("A13").End(Excel.XlDirection.xlToRight), Excel.Range).Column
            lastRow = CType(osheet.Range("A13").End(Excel.XlDirection.xlDown), Excel.Range).Row
            newDetails(i, 0) = tempName
            newDetails(i, 1) = lastRow
            newDetails(i, 2) = lastColumn
        Next
        owb.Close()

        Return newDetails
    End Function

    Function printNewDetails(ByVal details As Object(,)) As Integer
        For i = 0 To details.GetUpperBound(0)
            Console.WriteLine("New name: {0}", details(i, 0))
            Console.WriteLine("Last row: {0}", details(i, 1))
            Console.WriteLine("Last Column: {0}", details(i, 2))
        Next
        Return 1
    End Function

    Sub rename(ByVal oldName As String(), ByVal tempArray As Object(,))
        For i = 0 To oldName.GetUpperBound(0)
            FileSystem.RenameFile(oldName(i), CStr(tempArray(i, 0))) 'Error Here
        Next
    End Sub

End Module

我正在嘗試重命名一些 excel 文件,所有這些文件都在一個特定的目錄中。 該代碼執行以下操作:

  1. 它打開每個只有一張紙的文件
  2. 然后它在每個文件中選擇單元格 A7 中的字符串
  3. 它還找出數據集的最后一行和最后一列(單元格 A13 是每個文件中數據集的起點)
  4. 最后,在 object 數組newDetails中,我們將字符串存儲在單元格 A7 的第一列、數據集的最后一行(第 2 列)和數據集的最后一列(第 3 列)。 每行數據對應一個excel文件
  5. 之后,代碼使用rename子例程重命名文件——想法是將存儲在names數組中的舊名稱與newDetails數組第一列中的字符串值交換。

但是當我運行代碼時,會出現以下錯誤消息: The process cannot access the file because it is being used by another process 我打開了任務管理器,手動關閉了所有 excel 進程,甚至重新啟動了計算機 - 即使這樣也會出現此錯誤。 附上錯誤截圖。 請求幫助。 錯誤截圖

奇怪的是,當我多次運行代碼時,有時我會在owb = CType(oxl.Workbooks.Open(names(i)), Excel.Workbook)行中收到錯誤,並且該錯誤警告我檢查文件是否是否損壞。 這些文件沒有損壞,因為當我手動打開它們時沒有問題。 錯誤如下所示

當文件名以~$開頭時,通常表示該文件已經打開(在 Excel 中)。 但是,有時此文件不會被刪除。 如果您確定 Excel 不再運行,例如在重新啟動后,並且存在這樣的文件,則可以將其刪除。 當然,也可以在獲取文件列表時忽略它。

您沒有提到您使用的是.NET還是.NET Framework以及哪個版本。 VS 2019 支持 .NETCore 3.1、.NET 5( 不再支持)和 .NET Framework 版本。

可以考慮改用 NuGet package DocumentFormat.OpenXmlClosedXml 但是,如果希望使用Excel Interop ,請嘗試以下操作:

添加引用Microsoft Excel xx.x Object Library (例如:Microsoft Excel 16.0 Object 庫)

  • 項目
  • 添加項目參考...
  • COM
  • Microsoft Excel xx.x Object Library (例如:Microsoft Excel 16.0 Object 庫)
  • 好的

創建一個class (名稱:XLInfo.vb)

Public Class XLInfo
    Public Property OriginalFilename As String
    Public Property LastRow As Integer
    Public Property LastColumn As Integer
    Public Property RenamedTo As String
End Class

創建模塊(名稱:HelperExcel.vb)

Imports Microsoft.Office.Interop
Imports System.IO

Module HelperExcel
    Private Function GetExcelFilenames(folderPath As String) As List(Of String)
        Dim filenames As List(Of String) = New List(Of String)

        For Each fqFilename As String In Directory.GetFiles(folderPath, "*.xlsx")
            'get only the filename
            Dim fn As String = Path.GetFileName(fqFilename)

            If Not fn.StartsWith("~") Then
                Debug.WriteLine($"Info: adding '{fqFilename}'...")
                filenames.Add(fqFilename) 'add
            End If
        Next

        Return filenames
    End Function

    Public Function ProcessExcelFiles(folderPath As String) As List(Of XLInfo)
#Disable Warning CA1416
        Dim infos As List(Of XLInfo) = New List(Of XLInfo)

        Dim oxl As Excel.Application = Nothing
        Dim owbs As Excel.Workbooks = Nothing
        Dim owb As Excel.Workbook = Nothing
        Dim osheets As Excel.Worksheets = Nothing
        Dim osheet As Excel.Worksheet = Nothing
        Dim owr As Excel.Range = Nothing

        'get filenames
        Dim names As List(Of String) = GetExcelFilenames(folderPath)

        Try
            'create new instance
            oxl = New Excel.Application()

            oxl.Visible = False

            For i As Integer = 0 To names.Count - 1
                'create new instance
                Dim info As XLInfo = New XLInfo()

                'create reference
                Dim fn As String = names(i)

                'set value
                info.OriginalFilename = fn

                'open workbook
                'owb = oxl.Workbooks.Open(Filename:=fn, [ReadOnly]:=True)
                owb = oxl.Workbooks.Open(Filename:=fn)

                'open worksheet
                osheet = owb.Worksheets(1)

                'set value - this is the new filename
                info.RenamedTo = Path.Combine(Path.GetDirectoryName(fn), $"{osheet.Range("A7").Value.ToString()}.xlsx")

                'ToDo: get last column
                'set value - last column
                'info.LastColumn = DirectCast(osheet.Range("A13").End(Excel.XlDirection.xlToRight), Excel.Range).Column

                'ToDo: get last row
                'set value - last row
                'info.LastRow = DirectCast(osheet.Range("A13").End(Excel.XlDirection.xlDown), Excel.Range).Row

                'add
                infos.Add(info)

                If osheet IsNot Nothing Then
                    'release all resources
                    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(osheet)

                    'set value
                    osheet = Nothing
                End If

                If owb IsNot Nothing Then
                    'save
                    owb.SaveCopyAs(info.RenamedTo)
                    'owb.SaveAs2(Filename:=info.RenamedTo)

                    'close
                    owb.Close(False)

                    'release all resources
                    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(owb)

                    'set value
                    owb = Nothing
                End If
            Next
        Finally
            If osheet IsNot Nothing Then
                'release all resources
                System.Runtime.InteropServices.Marshal.FinalReleaseComObject(osheet)

                'set value
                osheet = Nothing
            End If

            If owb IsNot Nothing Then
                'close
                owb.Close(False)

                'release all resources
                System.Runtime.InteropServices.Marshal.FinalReleaseComObject(owb)

                'set value
                owb = Nothing
            End If

            If oxl IsNot Nothing Then
                'quit
                oxl.Quit()

                'release all resources
                System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oxl)

                'force garbage collection
                GC.Collect()
            End If
        End Try

#Enable Warning CA1416

        'sleep
        System.Threading.Thread.Sleep(250)

        'delete original filenames

        If Not Directory.Exists(Path.Combine(folderPath, "Original Files")) Then
            'create folder if it doesn't exist
            Directory.CreateDirectory(Path.Combine(folderPath, "Original Files"))
        End If

        For i As Integer = 0 To names.Count - 1
            If File.Exists(names(i)) Then
                'move file to .\Original Files\<filename>
                File.Move(names(i), Path.Combine(folderPath, "Original Files", Path.GetFileName(names(i))), True)
                Debug.WriteLine($"File moved to '{Path.Combine(folderPath, "Original Files", Path.GetFileName(names(i)))}'")

                'ToDo: if one desires to delete the original filenames,
                'uncomment the line below
                'delete file
                'File.Delete(names(i))
            End If
        Next

        Return infos
    End Function
End Module

注意:上面的代碼是用 VS 2022 (.NET 6) 測試的,因為不再支持 .NET 5。 有關更多信息,請參見此處 如果使用 .NET 框架,可以刪除#Disable Warning CA1416#Enable Warning CA1416

用法

Sub Main(args As String())
    'ToDo: replace folder name with desired folder name
    Dim infos As List(Of XLInfo) = ProcessExcelFiles("C:\Temp")

    For Each info As XLInfo In infos
        Dim msg As String = $"OriginalFilename: '{info.OriginalFilename}' RenamedTo: '{info.RenamedTo}' LastRow: '{info.LastRow}' LastColumn: '{info.LastColumn}'"
        Debug.WriteLine(msg)
        Console.WriteLine(msg)
    Next
End Sub

資源

其他資源

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM