Что нового

_ExcelSheetWriteFromArray ограничение количества выгружаемых строк

vovsla

Осваивающий
Сообщения
607
Репутация
36
В нижеуказанном примере не выгружается массив более 65000 строк.
Хотя, функция _ArrayDisplay отображает максимум 65524 строки...
Как можно обойти ограничение по количеству выгружаемых строк?

Код:
#include <Excel.au3>
#include <Array.au3>

$Excel=_ExcelBookNew()
$ArrSize=70000
Dim $Arr[$ArrSize][2]

For $Num=1 To $ArrSize-1
;~ 	$Arr[$Num]=$Num
	$Arr[$Num][0]=$Num
	$Arr[$Num][1]=$Num+1
Next

;~ _ArrayDisplay($Arr)
_ExcelSheetWriteFromArray($Excel, $Arr)




;~ -----------------------------------------------------------------------------_ExcelSheetWriteFromArray----------------------------------------------------------------------------
Func _ExcelSheetWriteFromArray($oExcel, ByRef $aArray, $iExcelStartRow = Default, $iExcelStartCol = Default, $iArrayStartRow = Default, $iArrayStartCol = Default, $iArrayEndRow = Default, $iArrayEndCol = Default)
Local $iExcelEndRow = 1
Local $iExcelEndCol = 1

If Not IsObj($oExcel) Then Return SetError(1, 0, 0)
If UBound($aArray, 0) <> 2 Then Return SetError(2, 0, 0)
If $iExcelStartRow = Default Then $iExcelStartRow = 1
If $iExcelStartCol = Default Then $iExcelStartCol = 1
If $iArrayStartRow = Default Then $iArrayStartRow = 0
If $iArrayStartCol = Default Then $iArrayStartCol = 0
If $iArrayEndRow = Default Then $iArrayEndRow = UBound($aArray) - 1
If $iArrayEndCol = Default Then $iArrayEndCol = UBound($aArray, 2) - 1
If $iExcelStartRow < 1 Then $iExcelStartRow = 1
If $iExcelStartCol < 1 Then $iExcelStartCol = 1
If $iArrayStartRow < 0 Then $iArrayStartRow = 0
If $iArrayStartCol < 0 Then $iArrayStartCol = 0
If $iArrayEndRow < $iArrayStartRow Then Return SetError(3, 1, 0)
If $iArrayEndCol < $iArrayStartCol Then Return SetError(4, 1, 0)
$iExcelEndRow = $iExcelStartRow + $iArrayEndRow - $iArrayStartRow
$iExcelEndCol = $iExcelStartCol + $iArrayEndCol - $iArrayStartCol

; Check if only part of the array is to written to the speadsheet
If $iArrayStartRow <> 0 Or $iArrayStartCol <> 0 Or $iArrayEndRow <> UBound($aArray) - 1 Or $iArrayEndCol = UBound($aArray, 2) - 1 Then
;Copy specified array range to a temporary array
Local $aTemp[$iArrayEndRow - $iArrayStartRow + 1][$iArrayEndCol - $iArrayStartCol + 1]
Local $iRow = 0
Local $iCol = 0
For $i = $iArrayStartRow To $iArrayEndRow
$iCol = 0
For $j = $iArrayStartCol To $iArrayEndCol
$aTemp[$iRow][$iCol] = $aArray[$i][$j]
$iCol += 1
Next
$iRow += 1
Next
With $oExcel.ActiveSheet
.Range(.Cells($iExcelStartRow, $iExcelStartCol), .Cells($iExcelEndRow, $iExcelEndCol)).Select
.Range(.Cells($iExcelStartRow, $iExcelStartCol), .Cells($iExcelEndRow, $iExcelEndCol)).value = $oExcel.Application.WorksheetFunction.Transpose($aTemp)
EndWith
Else
With $oExcel.ActiveSheet
.Range(.Cells($iExcelStartRow, $iExcelStartCol), .Cells($iExcelEndRow, $iExcelEndCol)).Select
.Range(.Cells($iExcelStartRow, $iExcelStartCol), .Cells($iExcelEndRow, $iExcelEndCol)).value = $oExcel.Application.WorksheetFunction.Transpose($aArray)
EndWith
EndIf

EndFunc ;==>_ExcelSheetWriteFromArray
 
A

Alofa

Гость
Цитата_1 из RU справки v3.3.8.1:
_ExcelWriteSheetFromArray
...
---------------
Внимание!!! документы разных форматов MS Office имеют различные ограничения по количеству столбцов и строк:
*.xls (формат xlExcel8, стандартный для MS Office 2003,97,95) имеет ограничения в 255 столбцов 65 535 строк
*.xlsx,*.xlsb,*.xlsm (XML-форматы MS Office 2007-2010) имеют ограничения в 16 384 столбца и 1 048 576 строк
...

Цитата_2 из RU справки v3.3.8.1:
_ExcelBookSaveAs
...
Примечания
В MS Office 2007-2010 доступен более расширенный список форматов "xlsx|xlsb|xlsm и т.д.",
"по умолчанию" используется формат "xlsx"
В базовой UDF "Excel.au3" использование в этой функции таких форматов не предусмотрено,
это можно исправить модифицированием "Excel.au3";
...


Добавлено:
Сообщение автоматически объединено:

Может стоит обновить версию библиотеки и Autoit?
Хотя бы для того чтобы заработала примерно нижеследующая конструкция:
Код:
#include <Array.au3>
#include <Excel.au3>

$ExOpen = _Excel_Open()
$oExcel= _Excel_BookNew($ExOpen)

$aArraySize=70000
Dim $aArray[$aArraySize][2]

For $Num=1 To $aArraySize-1
    $aArray[$Num][0] = $Num
    $aArray[$Num][1] = $Num+1
Next

;~ _ArrayDisplay($aArray)
_Excel_RangeWrite($oExcel, $oExcel.Activesheet, $aArray, "A1", True, True) ; Записываем массив

MsgBox(4096, "Отчет:", "Демонстрация завершена, нажмите ОК")
_Excel_BookSaveAs($oExcel, @ScriptDir & "\Temp.xlsx") ; Сохраняем файл в директории, перезаписывая если необходимо.
;~ _Excel_BookClose($oExcel) ; Закрываем рабочую книгу
;~ _Excel_Close($ExOpen) ; Закрываем Excel
 

Вложения

  • Excel.au3.7z
    7.3 КБ · Просмотры: 9
Автор
V

vovsla

Осваивающий
Сообщения
607
Репутация
36
При переходе на новую версию автоита придется переделывать довольно много готовых скриптов.
Хотя, можно попробовать добавить поддержку старых функций в новую версию
 
A

Alofa

Гость
Vovsla сказал(а):
Хотя, можно попробовать добавить поддержку старых функций в новую версию
Сизифов труд.
Я думаю, рано или поздно вы все равно придете к необходимости обновления библиотек.
К примеру, вышеописанный скрипт с новой версией "Excel.au3", которая работает с .xlsx, срабатывает за доли секунды (не считая заполнения массива), а старую я ждал несколько минут, даже компьютер вспотел.
 

ra4o

AutoIT Гуру
Сообщения
1,165
Репутация
246
можно попробовать добавить поддержку старых функций в новую версию
Для возможности работы со скриптами ранних версий - сохраните старую UDF 'Excel.au3' под другим именем, например '_Excel.au3' и достаточно изменить название библиотеки в '#include <_Excel.au3>' и будет работать Ваш скрипт с новой версией Autoit, но со старой UDF 'Excel.au3'.Как и писал Alofa- новые скрипты однозначно писать под новой UDF 'Excel.au3'.
 
Автор
V

vovsla

Осваивающий
Сообщения
607
Репутация
36
Да, я так и хотел попробовать, но если в скрипт добавить одновременно 'Excel.au3' и '_Excel.au3' и при этом в них попадутся одинаковые функции, то в старом придется немного поковыряться и закоментировать дубли
 

ra4o

AutoIT Гуру
Сообщения
1,165
Репутация
246
В одном скрипте может быть только одна из UDF - 'Excel.au3' или '_Excel.au3' , одновременно нельзя , хоть в них и одинаковых функций нет!
 
Автор
V

vovsla

Осваивающий
Сообщения
607
Репутация
36
А вот это очень печально. Может тогда в новую 'Excel.au3' вложить старую '_Excel.au3'? :smile:
 
A

Alofa

Гость
Vovsla
Вот это должно у вас заработать:
Код:
; Без #include

$ExOpen = _My_Excel_Open()
$oExcel = _My_Excel_BookNew($ExOpen)

$aArraySize = 700000 ; 700 тысяч!
Dim $aArray[$aArraySize][2]
For $Num = 1 To $aArraySize - 1
	$aArray[$Num][0] = $Num
	$aArray[$Num][1] = $Num + 1
Next
$hTimer = TimerInit()

_My_Excel_RangeWrite($oExcel, $oExcel.Activesheet, $aArray, "A1", True, True) ; Запись в книгу
_My_Excel_BookSaveAs($oExcel, @ScriptDir & "\Temp.xlsx", 1) ; Сохраняем в файл (Третий аргумент функции для перезаписи)
MsgBox(64, 'Отчет:', 'Запись завершена!')

;==============  Это функции из новой "Excel.au3" и "Array.au3", переименованные и слегка укороченные  =======================
Func _My_Excel_BookSaveAs($oWorkbook, $sFilePath, $bOverWrite = Default)
	If Not IsObj($oWorkbook) Or ObjName($oWorkbook, 1) <> "_Workbook" Then Return SetError(1, 0, 0)
	If $bOverWrite = Default Then $bOverWrite = False
	If FileExists($sFilePath) Then
		If Not $bOverWrite Then Return SetError(3, 0, 0)
		Local $iResult = FileDelete($sFilePath)
		If $iResult = 0 Then Return SetError(4, 0, 0)
	EndIf
	$oWorkbook.SaveAs($sFilePath, 51)
	If @error Then Return SetError(5, @error, 0)
	Return 1
EndFunc   ;==>_My_Excel_BookSaveAs

Func _My_Excel_RangeWrite($oWorkbook, $vWorksheet, $vValue, $vRange = Default, $bValue = Default, $bForceFunc = Default)
	If Not IsObj($oWorkbook) Or ObjName($oWorkbook, 1) <> "_Workbook" Then Return SetError(1, 0, 0)
	If Not IsObj($vWorksheet) Then
		If $vWorksheet = Default Then
			$vWorksheet = $oWorkbook.ActiveSheet
		Else
			$vWorksheet = $oWorkbook.WorkSheets.Item($vWorksheet)
		EndIf
		If @error Or Not IsObj($vWorksheet) Then Return SetError(2, @error, 0)
	ElseIf ObjName($vWorksheet, 1) <> "_Worksheet" Then
		Return SetError(2, @error, 0)
	EndIf
	If $vRange = Default Then $vRange = "A1"
	If $bValue = Default Then $bValue = True
	If $bForceFunc = Default Then $bForceFunc = False
	If Not IsObj($vRange) Then
		$vRange = $vWorksheet.Range($vRange)
		If @error Or Not IsObj($vRange) Then Return SetError(3, @error, 0)
	EndIf
	If Not IsArray($vValue) Then
		If $bValue Then
			$vRange.Value = $vValue
		Else
			$vRange.Formula = $vValue
		EndIf
		If @error Then Return SetError(4, @error, 0)
	Else
		If $vRange.Columns.Count = 1 And $vRange.Rows.Count = 1 Then
			If UBound($vValue, 0) = 1 Then
				$vRange = $vRange.Resize(UBound($vValue, 1), 1)
			Else
				$vRange = $vRange.Resize(UBound($vValue, 1), UBound($vValue, 2))
			EndIf
		EndIf

		If $bForceFunc Then
			If UBound($vValue, 0) = 1 Then ; _ArrayTranspose only works for 2D arrays so we do it ourselfs for 1D arrays
				Local $aTemp[1][UBound($vValue, 1)]
				For $z = 0 To UBound($vValue, 1) - 1
					$aTemp[0][$z] = $vValue[$z]
				Next
				$vValue = $aTemp
			Else
				_My_ArrayTranspose($vValue)
			EndIf
			If $bValue Then
				$vRange.Value = $vValue
			Else
				$vRange.Formula = $vValue
			EndIf
			If @error Then Return SetError(4, @error, 0)
		Else
			Local $oExcel = $oWorkbook.Parent
			If $bValue Then
				$vRange.Value = $oExcel.Transpose($vValue)
			Else
				$vRange.Formula = $oExcel.Transpose($vValue)
			EndIf
			If @error Then Return SetError(4, @error, 0)
		EndIf
	EndIf
	Return $vRange
EndFunc   ;==>_My_Excel_RangeWrite

Func _My_ArrayTranspose(ByRef $avArray)
	Switch UBound($avArray, 0)
		Case 0
			Return SetError(2, 0, 0)
		Case 1
			Local $aTemp[1][UBound($avArray)]
			For $i = 0 To UBound($avArray) - 1
				$aTemp[0][$i] = $avArray[$i]
			Next
			$avArray = $aTemp
			Return 1
		Case 2
			Local $vElement, $iDim_1 = UBound($avArray, 1), $iDim_2 = UBound($avArray, 2), $iDim_Max = $iDim_1
			If $iDim_2 > $iDim_1 Then $iDim_Max = $iDim_2
			If $iDim_Max <= 4096 Then
				ReDim $avArray[$iDim_Max][$iDim_Max]
				For $i = 0 To $iDim_Max - 2
					For $j = $i + 1 To $iDim_Max - 1
						$vElement = $avArray[$i][$j]
						$avArray[$i][$j] = $avArray[$j][$i]
						$avArray[$j][$i] = $vElement
					Next
				Next
				If $iDim_1 = 1 Then
					Local $aTemp[$iDim_2]
					For $i = 0 To $iDim_2 - 1
						$aTemp[$i] = $avArray[$i][0]
					Next
					$avArray = $aTemp
				Else
					ReDim $avArray[$iDim_2][$iDim_1]
				EndIf
			Else
				Local $aTemp[$iDim_2][$iDim_1]
				For $i = 0 To $iDim_1 - 1
					For $j = 0 To $iDim_2 - 1
						$aTemp[$j][$i] = $avArray[$i][$j]
					Next
				Next
				ReDim $avArray[$iDim_2][$iDim_1]
				$avArray = $aTemp
			EndIf
			Return 1
		Case Else
			Return SetError(1, 0, 0)
	EndSwitch
EndFunc   ;==>_My_ArrayTranspose

Func _My22_Excel_RangeWrite($oWorkbook, $vWorksheet, $vValue, $vRange = Default)
	If Not IsObj($oWorkbook) Or ObjName($oWorkbook, 1) <> "_Workbook" Then Return SetError(1, 0, 0)
	If Not IsObj($vWorksheet) Then
		If $vWorksheet = Default Then
			$vWorksheet = $oWorkbook.ActiveSheet
		Else
			$vWorksheet = $oWorkbook.WorkSheets.Item($vWorksheet)
		EndIf
		If @error Or Not IsObj($vWorksheet) Then Return SetError(2, @error, 0)
	ElseIf ObjName($vWorksheet, 1) <> "_Worksheet" Then
		Return SetError(2, @error, 0)
	EndIf
	If $vRange = Default Then $vRange = "A1"
	If Not IsObj($vRange) Then
		$vRange = $vWorksheet.Range($vRange)
		If @error Or Not IsObj($vRange) Then Return SetError(3, @error, 0)
	EndIf
	If Not IsArray($vValue) Then
		$vRange.Value = $vValue
		If @error Then Return SetError(4, @error, 0)
	Else
		If $vRange.Columns.Count = 1 And $vRange.Rows.Count = 1 Then
			If UBound($vValue, 0) = 1 Then
				$vRange = $vRange.Resize(UBound($vValue, 1), 1)
			Else
				$vRange = $vRange.Resize(UBound($vValue, 1), UBound($vValue, 2))
			EndIf
		EndIf
		Local $oExcel = $oWorkbook.Parent
		$vRange.Value = $oExcel.Transpose($vValue)
		If @error Then Return SetError(4, @error, 0)
	EndIf
	Return $vRange
EndFunc   ;==>_My22_Excel_RangeWrite

Func _My_Excel_Open()
	Local $oExObj
	Static $bState[101] = [0]
	$oExObj = ObjCreate("Excel.Application")
	If @error Or Not IsObj($oExObj) Then Return SetError(1, @error, 0)
	For $i = 1 To $bState[0]
		If Not IsObj($bState[$i]) Or $bState[$i] = $oExObj Then ; Empty cell found or instance already stored
			$bState[$i] = $oExObj
			Return True
		EndIf
	Next
	$bState[0] = $bState[0] + 1 ; No empty cell found and instance not already in table. Create a new entry at the end of the table
	$bState[$bState[0]] = $oExObj
	$oExObj.Visible = True
	$oExObj.DisplayAlerts = False
	$oExObj.ScreenUpdating = True
	$oExObj.Interactive = True
	Return $oExObj
EndFunc   ;==>_My_Excel_Open

Func _My_Excel_BookNew($oExcel, $iSheets = Default)
	If Not IsObj($oExcel) Or ObjName($oExcel, 1) <> "_Application" Then Return SetError(1, 0, 0)
	With $oExcel
		If $iSheets <> Default Then
			If $iSheets > 255 Then Return SetError(4, 0, 0)
			Local $iSheetsBackup = .SheetsInNewWorkbook
			.SheetsInNewWorkbook = $iSheets
			If @error Then Return SetError(2, @error, 0)
		EndIf
		Local $oWorkbook = .Workbooks.Add()
		If @error Then
			Local $iError = @error
			If $iSheets <> Default Then .SheetsInNewWorkbook = $iSheetsBackup
			Return SetError(3, $iError, 0)
		EndIf
		If $iSheets <> Default Then .SheetsInNewWorkbook = $iSheetsBackup
	EndWith
	Return $oWorkbook
EndFunc   ;==>_My_Excel_BookNew

Но учтите, что на выходе получается *.xlsx.
 

ra4o

AutoIT Гуру
Сообщения
1,165
Репутация
246
Может тогда в новую 'Excel.au3' вложить старую '_Excel.au3'
зачем ? Вы обновляете AutoIt до свежей версии, предварительно сохранив старую UDF 'Excel.au3' под другим именем лишь для того, что-бы была возможность работать со скриптами, написанными ранее, новые пишите используя новую UDF 'Excel.au3', в одном скрипте старая с новой UDF 'Excel.au3' пересекаться не будут и смысла их лепить вместе нет никакого.
 
A

Alofa

Гость
ra4o сказал(а):
Вы обновляете AutoIt до свежей версии, предварительно сохранив старую UDF 'Excel.au3' под другим именем лишь для того, что-бы была возможность работать со скриптами, написанными ранее ...
Тут может быть не все так просто. В самих библиотеках, как правило, тоже есть #include, а те, подключаемые библиотеки, в свою очередь тоже подключаются к следующим - так можно выстроить довольно длинную цепочку.
Я бы посоветовал попробовать переместить всю папку "\include"
со старыми библиотеками в новую (прямо так - папкой). А для того чтобы ваши старые скрипты работали - изменить в них только путь до нужных библиотек.
 
Автор
V

vovsla

Осваивающий
Сообщения
607
Репутация
36
Да, не все так просто. Положил старую библиотеку назвав ее Excel10.2.au3, прописал в скрипте - все работает
Добавил в скрипт новую библиотеку Excel.au3 и началось, ругается на объявление констант в библиотеке Excel10.2.au3, говорит что они уже ранее объявлены.
Когда заремил объявление констант в Excel10.2.au3, там же появляется ошибка с сообщением что переменная не объявлена - та константа которую заремил


Добавлено:
Сообщение автоматически объединено:

После заремливания констант добавил в старую библиотеку <ExcelConstants.au3> и все поехало
 
Верх