Что нового

[Файловая система] получить в переменную содержимое файла, находящегося в 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,322
ZloePelme666ko,
Дайте пример zip-файла.
 
Автор
ZloePelme666ko

ZloePelme666ko

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


http://zalil.ru/34811294

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

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

Но я не понял как из нее потом вытащить содержимое, если это вообще возможно
 

madmasles

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

ZloePelme666ko

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

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Код:
#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,322
Viktor1703,
А как только прочитать файл(ы)?
 
Автор
ZloePelme666ko

ZloePelme666ko

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

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
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])
 
Верх