Что нового

[Файловая система] получить в переменную содержимое файла, находящегося в ZIP архиве

ZloePelme666ko

Новичок
Сообщения
18
Репутация
1
Собственно была поставлена задача: прогружать в базу SQLite3 отчетные данные, которые приходят в формате XML(порядка 150 000 файлов до 100Кб каждый), собранные в ZIP-архив :stars:. с sqlite3.dll и msxml.dll вопросов не возникло. Пробовал распаковывать в папку и перебирать поштучно с последующим удалением - вышло 12 часов на один архив. И долго, и для винта очень вредно. Вот и возник очевидный вопрос: можно ли какими-нибудь средствами читать содержимое файла из архива сразу в переменную, минуя запись на HDD?

Только не кричите что не умею пользоваться поиском - искал :smile:. И вот что нашел: http://autoit-script.ru/index.php?PHPSESSID=sheaagdl7e9dvklh4rim7o8i21&topic=11218.0
Там эта функция реализована, даже есть в примере, но когда я произвожу перебор файлов то функция отдает содержимое только первого файла, а содержимое последующих забиты нулями, хотя имя возвращает верное :wall_brake:

Вот мой код под эту UDF:
Код:
#include <uZip.au3>

Global $sPackage = @ScriptDir & '\KM_2000140_2013_09.zip' ;~ Имя архива.
_uZip_Startup()

$Index=0
While 1
	If _uZip_GetFileInfo($sPackage, $Index) Then ;в качестве теста получаю окно с информацией по файлу
		MsgBox(0,'GetFileInfo', 'Compressed size: ' & @TAB & @TAB & _uZip_GetCompressedSize() & @CRLF & _
		         'Compression method: ' & @TAB & _uZip_GetCompressionMethod() & @CRLF & _
		         'CRC32: ' & @TAB & @TAB & @TAB & _uZip_GetCrc32() & @CRLF & _
		         'External file attributes: ' & @TAB & _uZip_GetExternalFileAttributes() & @CRLF & _
		         'File name: ' & @TAB & @TAB & _uZip_GetFileName() & @CRLF & _
		         'IsPassword: ' & @TAB & @TAB & _uZip_GetFlag() & @CRLF & _
		         'Internal file attributes: ' & @TAB & _uZip_GetInternalFileAttributes() & @CRLF & _
		         'Size file name: ' & @TAB & @TAB & _uZip_GetSizeFileName() & @CRLF & _
		         'File date: ' & @TAB & @TAB & _uZip_GetFileDate() & @CRLF & _
		         'Uncompressed size: ' & @TAB & _uZip_GetUnCompressedSize() & @CRLF & _
		         'Version needed: ' & @TAB & @TAB & _uZip_GetVersionNeeded())
	EndIf
	$name = _uZip_GetFileName()
	if $name = '' then ExitLoop; уходим из цикла по достижении конца архива
	FileDelete($name); удаляем если уже существовал
	$data = _uZip_LoadToMemoryEx($sPackage, $name)
	FileWrite($name,$data)
	$index+=1
WEnd


Собственно 2 вопроса:
1. Если кто видит ошибку здесь - прошу тыкните носом :-[
2. Есть ли какие-нибудь другие средства для достижения моей цели?
 

madmasles

Модератор
Глобальный модератор
Сообщения
7 790
Репутация
2 319
ZloePelme666ko,
Дайте пример zip-файла.
 
Автор
ZloePelme666ko

ZloePelme666ko

Новичок
Сообщения
18
Репутация
1
madmasles , вот. Вынул 99% из архива для облегчения, суть думаю от этого не поменяется.


http://zalil.ru/34811294

Уповаю на вашу осведомленность :smile:

ps там есть еще функция такая:
Код:
;~ Загружаем файл из ахива в память и получаем указатель на область памяти.
$pMem = _uZip_LoadToMemory($sPackage, $fName, $sPassword)
Но я не понял как из нее потом вытащить содержимое, если это вообще возможно
 

madmasles

Модератор
Глобальный модератор
Сообщения
7 790
Репутация
2 319
ZloePelme666ko [?]
Уповаю на вашу осведомленность
Зря, пока у меня ничего не получилось. :(
Будем ждать, когда ответит автор библиотеки Viktor1703. Самому стало интересно.
 
Автор
ZloePelme666ko

ZloePelme666ko

Новичок
Сообщения
18
Репутация
1
madmasles, оч надеюсь... иначе где то тут видел темку про создание виртуального диска в озу :blum:uke: Я конечно умею работать через ж :Censored: у, но ведь не хочется
 

Viktor1703

AutoIT Гуру
Сообщения
1 535
Репутация
411
Код:
#include <uZip.au3>

Global $Index = 0, $sPackage = @ScriptDir & '\KM_2000140_2013_09.zip'

_uZip_Startup()

While 1
	If _uZip_GetFileInfo($sPackage, $Index) Then
		_uZip_SaveToFile($sPackage, _uZip_GetFileName())
	    $Index += 1
	Else
		ExitLoop
	EndIf
WEnd

_uZip_Shutdown()
 

madmasles

Модератор
Глобальный модератор
Сообщения
7 790
Репутация
2 319
Viktor1703,
А как только прочитать файл(ы)?
 
Автор
ZloePelme666ko

ZloePelme666ko

Новичок
Сообщения
18
Репутация
1
Viktor1703 задача не грузить их на диск, и потом читать(ибо их в архивах тонны) а читать прямо из архива :smile:
 

Viktor1703

AutoIT Гуру
Сообщения
1 535
Репутация
411
madmasles, ZloePelme666ko, мой косяк... придётся поднимать исходники, сейчас гляну...
 

sims

Осваивающий
Сообщения
184
Репутация
24
Почему бы не использовать спец библиотеки для zip архивов?
Есть же minizip.lib и zlib.lib. Они позволят извлечь файл из архива в память (функция unzReadCurrentFile) и не нужно в месте с прогой распространять dll.
 
Автор
ZloePelme666ko

ZloePelme666ko

Новичок
Сообщения
18
Репутация
1
sims
Спасибо за наводку, буду копать в ту сторону! :dance1: Как только таймер спадет отмечу полезным))) завтра гляну, а сейчас уже сплю почти на ходу :sleeping:


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

Viktor1703
спасибо огромное :laugh: Где вам удобней отвечать? а то я тут почти одно и то же пишу в обе темы) :whistle:
 
Автор
ZloePelme666ko

ZloePelme666ko

Новичок
Сообщения
18
Репутация
1
sims
Вчера почитал про zlib и minizip... Заглянул в инклюды сишные и.... ничего не понял :( не силён я
Если вам не сложно - не могли бы поделиться экспириенсом?
 

sims

Осваивающий
Сообщения
184
Репутация
24
ZloePelme666ko [?]
Заглянул в инклюды сишные
Речь шла об статических библиотеках. http://ru.wikipedia.org/wiki/Библиотека_(программирование)#.D0.A1.D1.82.D0.B0.D1.82.D0.B8.D1.87.D0.B5.D1.81.D0.BA.D0.B8.D0.B5_.D0.B1.D0.B8.D0.B1.D0.BB.D0.B8.D0.BE.D1.82.D0.B5.D0.BA.D0.B8
В отличие от динамических (dll), статические (lib) добавляются в исполняемый файл во время компиляции.
Только я все время забываю что в AutoIt не компилятора, а значит нет и линкера...
Наверное стоит подождать исправление dll от Viktor1703.
 
Автор
ZloePelme666ko

ZloePelme666ko

Новичок
Сообщения
18
Репутация
1
sims жду :smile: но это же не мешает рассматривать другие варианты. Я нашёл zlib.dll, посмотрел схему включения, но дальше открытия и закрытия архивов не смог накрутить... Не понял че передавать в функцию unzGetCurrentFileInfo. Могу выложить если кому интересно
 

sims

Осваивающий
Сообщения
184
Репутация
24
Работать с zlib.dll из автоита будет слегка хлопотно из-за не очень удобной работы со структурами.
Сделал обертку над zlib.lib, позволяющую по максимуму упростить работу с ней. Пример перечисления всех файлов архива.
Код:
const $CompressedSize   = 1 ; Размер сжатого файла.
const $UncompressedSize = 0 ; Размер распакованого файла.

$dll = dllopen("AutoIt_zip.dll")
if $dll > -1 then
  $return = dllcall($dll, 'int', 'Open', 'str', 'C:\Archive.zip')
  if $return[0] <> 0 Then
	 $return = dllcall($dll, 'int', 'Enum_Start')
	 if $return[0] <> 0 Then
		
		while 1
		   $return = dllcall($dll, 'int', 'Enum_Next')
		   if $return[0] = 0 then
			  ExitLoop
		   endif
		   
		    $return = dllcall($dll, 'str', 'Enum_FileName')
			$Infa = 'Файл ' & $return[0] & chr(10) & 'Размер '
			$return = dllcall($dll, 'int', 'Enum_Size', 'int', $UncompressedSize)
			$Infa = $Infa & $return[0]
		   
		   MsgBox(0, '', $Infa, 0)	   
	    wend
     endif
	 dllcall($dll, 'int', 'Close')
  endif
  DllClose($dll)
endif
Сначала открывается архив. Зачем вызывается функция Enum_Start начинаюшая перечисление файлов. Потом нужно в цикле вызывать Enum_Next и если вернет 0, то все файлы архива были перечислены. За этой функцией можно вызвать Enum_FileName, возвращающую имя файла текущего перечиения. Функция Enum_Size вернет размер файла. В зависимости от типа ($CompressedSize или $UncompressedSize) это будет размер сжатого или распакованого файла. Есть еще одна функция Uncompress_Memory, распаковывающая в память файл текущего перечисления. Ей нужно передать через параметры (их два) указатель на память размера не меньше чем распакованный файл и размер распакованого файла. Размер можно узнать функцией Enum_Size и констрантой $UncompressedSize.
 
Автор
ZloePelme666ko

ZloePelme666ko

Новичок
Сообщения
18
Репутация
1
sims
Код:
$zipfile='D:\яДиск\ZipMafaka\KM_2000140_2013_09.zip'
 $return = dllcall($dll, 'int', 'Open', 'str',$zipfile)

-Умер прям на старте
Код:
$return = dllcall($dll, 'int', 'Open', 'str','D:\яДиск\ZipMafaka\KM_2000140_2013_09.zip')

-работает нормально

Как так?)))


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

И еще, sims , я так понял что можно все таки этой штукой читать в память... в memory.au3 можно тока резервировать участок памяти через _MemGlobalAlloc($iBytes[, $iFlags = 0]), а как из него потом это вытащить...с помощью nomadmemory.au3?
 

sims

Осваивающий
Сообщения
184
Репутация
24
Работает независимо от того, где путь в переменной или нет.

Функция _MemGlobalAlloc должна вернуть указатель на память. Его сначала нужно передать функции Uncompress_Memory, чтобы в память извлекся файл, а затем msxml.dll для дальнейшей обработки.
 
Автор
ZloePelme666ko

ZloePelme666ko

Новичок
Сообщения
18
Репутация
1
sims, спасибо) Буду ща думать как лучше этот кусок памяти в переменную запихнуть чтоб в msxml передать, а то Viktor1703 видимо пока не смог решить проблему...правда его udf подошла бы намного больше, так как потом базы sqlite надо бы тоже архивировать...


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

sims, прости еще раз, я наверное туп как пень.. не могу понять как в автоите вытащить данные из памяти
Код:
const $CompressedSize   = 1 ; Размер сжатого файла.
const $UncompressedSize = 0 ; Размер распакованого файла.

$zipfile=FileOpenDialog('Выбери зип',@ScriptDir,'ZIP-file(*.zip)')

$dll = dllopen("AutoIt_zip.dll")
if $dll > -1 then
  $return = dllcall($dll, 'int', 'Open', 'str',$zipfile)
  if $return[0] <> 0 Then
	 $return = dllcall($dll, 'int', 'Enum_Start')
	 if $return[0] <> 0 Then
		while 1
		   $return = dllcall($dll, 'int', 'Enum_Next')
		   if $return[0] = 0 then
			  ExitLoop
		   endif

		    $return = dllcall($dll, 'str', 'Enum_FileName')
			$Infa = 'Файл ' & $return[0] & chr(10) & 'Размер '
			$return = dllcall($dll, 'int', 'Enum_Size', 'int', $UncompressedSize)
			$Infa = $Infa & $return[0]


		   MsgBox(0, '', $Infa, 0)

			$memory = _MemGlobalAlloc ($UncompressedSize,0x0000)

			$return = dllcall($dll, 'int', 'Uncompress_Memory', 'ptr', $memory, 'int', $UncompressedSize)

;===========> КАК ТЕПЕРЬ ИЗ ПАМЯТИ ВЫДЕРНУТЬ ТО ЧТО ЛЕЖИТ ПО АДРЕСУ $memory? <======
	    wend
     endif
	 dllcall($dll, 'int', 'Close')
  endif
  DllClose($dll)
endif

Func _MemGlobalAlloc($iBytes, $iFlags = 0)
	Local $aResult = DllCall("kernel32.dll", "handle", "GlobalAlloc", "uint", $iFlags, "ulong_ptr", $iBytes)
	If @error Then Return SetError(@error, @extended, 0)
	Return $aResult[0]
EndFunc
 

sims

Осваивающий
Сообщения
184
Репутация
24
Функции требуют размер распакованого файла, а не константу. Должно быть.
Код:
$memory = _MemGlobalAlloc($return[0],0x0000)

            $return = dllcall($dll, 'int', 'Uncompress_Memory', 'ptr', $memory, 'int', $return[0])
 
Верх