2013-03-20 56 views
7

我有MS Excel文檔通過Powershell接口。每個excel文件有大約1000行數據的可能性。用Powershell解析excel文檔有沒有更快的方法?

目前這個劇本似乎讀取Excel文件,並在每個0.6秒1個記錄的速度值寫入屏幕。乍一看,這似乎非常緩慢。

這是我第一次讀取Excel文件,Powershell,這是正常的?有沒有更快的方式來讀取和解析Excel數據?

這裏是腳本輸出(修剪可讀性)

PS P:\Powershell\ExcelInterfaceTest> .\WRIRMPTruckInterface.ps1 test.xlsx 
3/20/2013 4:46:01 PM 
--------------------------- 
2 078110 
3 078108 
4 078107 
5 078109 
<SNIP> 
242 078338 
243 078344 
244 078347 
245 078350 
3/20/2013 4:48:33 PM 
--------------------------- 
PS P:\Powershell\ExcelInterfaceTest> 

這裏是Powershell腳本:

######################################################################################################## 
# This is a common function I am using which will release excel objects 
######################################################################################################## 
function Release-Ref ($ref) { 
    ([System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$ref) -gt 0) 
    [System.GC]::Collect() 
    [System.GC]::WaitForPendingFinalizers() 
} 

######################################################################################################## 
# Variables 
######################################################################################################## 

######################################################################################################## 
# Creating excel object 
######################################################################################################## 
$objExcel = new-object -comobject excel.application 

# Set to false to not open the app on screen. 
$objExcel.Visible = $False 

######################################################################################################## 
# Directory location where we have our excel files 
######################################################################################################## 
$ExcelFilesLocation = "C:/ShippingInterface/" + $args[0] 

######################################################################################################## 
# Open our excel file 
######################################################################################################## 
$UserWorkBook = $objExcel.Workbooks.Open($ExcelFilesLocation) 

######################################################################################################## 
# Here Item(1) refers to sheet 1 of of the workbook. If we want to access sheet 10, we have to modify the code to Item(10) 
######################################################################################################## 
$UserWorksheet = $UserWorkBook.Worksheets.Item(2) 

######################################################################################################## 
# This is counter which will help to iterrate trough the loop. This is simply a row counter 
# I am starting row count as 2, because the first row in my case is header. So we dont need to read the header data 
######################################################################################################## 
$intRow = 2 

$a = Get-Date 
write-host $a 
write-host "---------------------------" 

Do { 

    # Reading the first column of the current row 
    $TicketNumber = $UserWorksheet.Cells.Item($intRow, 1).Value() 

    write-host $intRow " " $TicketNumber  

    $intRow++ 

} While ($UserWorksheet.Cells.Item($intRow,1).Value() -ne $null) 

$a = Get-Date 
write-host $a 
write-host "---------------------------" 

######################################################################################################## 
# Exiting the excel object 
######################################################################################################## 
$objExcel.Quit() 

######################################################################################################## 
#Release all the objects used above 
######################################################################################################## 
$a = Release-Ref($UserWorksheet) 
$a = Release-Ref($UserWorkBook) 
$a = Release-Ref($objExcel) 

回答

6

如果數據是靜態的(沒有公式參與,只是在單元格數據)您可以作爲ODBC數據源訪問電子表格,並對其執行SQL(或至少類似SQL)查詢。看看this reference設置你的ConnectionString(在工作簿將成爲這項工作一「表」每個工作表),並使用System.Data查詢它和你一樣將常規數據庫(唐·瓊斯爲此寫了一wrapper function其可能有幫助)。

這個應該比啓動Excel &更快地通過細胞逐個挑選。

+0

這是非常有趣的,我給它一個鏡頭的明天,看看它是如何執行。 – ProfessionalAmateur 2013-03-21 02:02:40

+0

這太好了。瘋狂地更快。 – ProfessionalAmateur 2013-03-22 18:24:44

7

在他的博客中Speed Up Reading Excel Files in PowerShell,羅伯特·Toups,小解釋說,雖然加載到PowerShell是快速,實際上讀取Excel單元格很慢。在另一方面,PowerShell中可以讀取的文本文件非常快,所以他的解決辦法是加載在PowerShell中的電子表格,使用Excel自帶的CSV出口過程中,將其保存爲CSV文件,然後使用PowerShell的標準Import-Csv cmdlet來超炫處理數據快速。他報道說這使他的進口過程快了20倍!

利用Toups’代碼,我創建了一個Import-Excel功能,您可以導入電子表格數據變得非常容易。 我的代碼添加了在Excel工作簿中選擇特定工作表的功能,而不是僅使用默認工作表(即保存文件時的活動工作表)。如果您省略–SheetName參數,它將使用默認工作表。

function Import-Excel([string]$FilePath, [string]$SheetName = "") 
{ 
    $csvFile = Join-Path $env:temp ("{0}.csv" -f (Get-Item -path $FilePath).BaseName) 
    if (Test-Path -path $csvFile) { Remove-Item -path $csvFile } 

    # convert Excel file to CSV file 
    $xlCSVType = 6 # SEE: http://msdn.microsoft.com/en-us/library/bb241279.aspx 
    $excelObject = New-Object -ComObject Excel.Application 
    $excelObject.Visible = $false 
    $workbookObject = $excelObject.Workbooks.Open($FilePath) 
    SetActiveSheet $workbookObject $SheetName | Out-Null 
    $workbookObject.SaveAs($csvFile,$xlCSVType) 
    $workbookObject.Saved = $true 
    $workbookObject.Close() 

    # cleanup 
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbookObject) | 
     Out-Null 
    $excelObject.Quit() 
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($excelObject) | 
     Out-Null 
    [System.GC]::Collect() 
    [System.GC]::WaitForPendingFinalizers() 

    # now import and return the data 
    Import-Csv -path $csvFile 
} 

這些補充功能是使用進口的Excel:

function FindSheet([Object]$workbook, [string]$name) 
{ 
    $sheetNumber = 0 
    for ($i=1; $i -le $workbook.Sheets.Count; $i++) { 
     if ($name -eq $workbook.Sheets.Item($i).Name) { $sheetNumber = $i; break } 
    } 
    return $sheetNumber 
} 

function SetActiveSheet([Object]$workbook, [string]$name) 
{ 
    if (!$name) { return } 
    $sheetNumber = FindSheet $workbook $name 
    if ($sheetNumber -gt 0) { $workbook.Worksheets.Item($sheetNumber).Activate() } 
    return ($sheetNumber -gt 0) 
} 
+0

'Import-CSV'能否讓您選擇特定的單元格和列數據? – ProfessionalAmateur 2013-03-21 17:13:23

+0

命令行工具的最佳實踐(回到Unix時代)是它應該做好一件事情。所以Import-Csv只是導入整個事情。但是,您只需應用PowerShell的強大功能,通常是「Where-Object」選擇行,「Select-Object」選擇列。 – 2013-03-21 18:45:28

+0

呃我檢查一下。因爲excel數據的格式不一致,所以要堅持下去。柱狀數據在整個一天都不統一。我會和它一起玩,看看。我可能需要將powershell保存爲CSV文件,因爲不會有任何用戶交互獲取這些文件。 – ProfessionalAmateur 2013-03-21 19:06:09

相關問題