Read and write files directly from/to Archive without extracting to the disk

Post your working scripts, libraries and tools
Nagendra
Posts: 11
Joined: 25 May 2017, 02:23

Read and write files directly from/to Archive without extracting to the disk

15 Jul 2018, 11:23

Hello everyone!

After so many attempts, finally succeeded in directly reading and writing from archive files without extracting to the disk.

I am not really sure if someone attempted this already. Searched in the forum but couldn’t find anything.

The final solution is so simple. But it took many trial and errors by evaluating different methods. Some of them worked, but with some shortfalls. I will explain “those” other methods in the end and the problems that I encountered. I hope it saves some time for anyone who is interested to check other possibilities.

Ok. Now, this is just a wrapper for 7-Zip (Undoubtedly, a brilliant piece of software).
7-Zip supports Stdin/Stdout functions. Directly writing and reading in console without extracting to the disk. The switches are “-si” and “-so”

There are 3 script files:
First one is 7-Zip Library (Wrapper for 7z.exe)
Second one is the “Support Script”
And the third is the “Example Script”

And rest all is self-explanatory.
7-Zip Library.ahk

Code: Select all

/*
=============================================================================================
7-Zip Functions
=============================================================================================
*/
7z_ReadFileFromArchive(ArchiveName, FileNameToRead)
{
	Global 7ZCmd
	CommandRead = "%7ZCmd% x "%ArchiveName%" %FileNameToRead% -so"
	return ShellCmdOut(CommandRead)	
}

7z_WriteFileToArchive(ArchiveName, FileNameToWrite, TextToWrite)
{
	Global 7ZCmd
	SupportScript = "%A_ScriptDir%\WriteInConsoleNew.ahk"
	Run, Notepad.exe,,Hide, PID
	WinWait, ahk_pid %PID%
	WinSetTitle, ahk_pid %PID%,,Script Share
	ControlSetText, Edit1, %TextToWrite%, ahk_pid %PID%
	CommandWrite = ""%A_AhkPath%" %SupportScript%"" %PID%|more|%7ZCmd% u "%ArchiveName%" -si"%FileNameToWrite%""
	CmdOut := ShellCmdOut(CommandWrite)
	return Check := Instr(CmdOut, "Everything is Ok") ? 1 : 0
}

7z_TestArchive(ArchiveName)
{
	Global 7ZCmd
	TestCommand = "%7ZCmd% t "%ArchiveName%""
	Output := ShellCmdOut(TestCommand)
	TestArray := {}
	If(Instr(Output, "Everything is Ok"))
		TestArray["Integrity"] := "OK"
	else
		TestArray["Integrity"] := "Not OK"
	Loop, Parse, Output, `n, `r
	{
		If !A_LoopField
			continue
		If(Instr(A_LoopField, "file", 1) && Instr(A_LoopField, "bytes", 1))
			TestArray["FileSize"] := SubStr(A_LoopField, Instr(A_LoopField, ",") + 2)
		Else If(Instr(A_LoopField, "Type = ", 1))
			TestArray["Type"] := SubStr(A_LoopField, 8)
		Else If(Instr(A_LoopField, "Physical Size = ", 1))
			TestArray["PhysicalSize"] := SubStr(A_LoopField, 17)
		Else If(Instr(A_LoopField, "Headers Size = ", 1))
			TestArray["HeadersSize"] := SubStr(A_LoopField, 16)
		Else If(Instr(A_LoopField, "Method = ", 1))
			TestArray["Method"] := SubStr(A_LoopField, 10)
		Else If(Instr(A_LoopField, "Folders: ", 1))
			TestArray["Folders"] := SubStr(A_LoopField, 10)
		Else If(Instr(A_LoopField, "Files: ", 1))
			TestArray["Files"] := SubStr(A_LoopField, 8)
		Else If(Instr(A_LoopField, "Size: ", 1))
			TestArray["OriginalSize"] := SubStr(A_LoopField, 13)
		Else If(Instr(A_LoopField, "Compressed: ", 1))
			TestArray["CompressedSize"] := SubStr(A_LoopField, 13)
		else
			Continue
	}
	return TestArray
}

ShellCmdOut(command)
{
	dhw := A_DetectHiddenWindows
	DetectHiddenWindows On
	Run "%ComSpec%" /k,, Hide, pid
	while !(hConsole := WinExist("ahk_pid" pid))
		Sleep 10
	DllCall("AttachConsole", "UInt", pid)
	DetectHiddenWindows %dhw%

	Shell := ComObjCreate("WScript.Shell").Exec(ComSpec " /C " command)
	xOutput := shell.StdOut.ReadAll()
	xError := shell.StdErr.ReadAll()
	
	DllCall("FreeConsole")
	Process Exist, %pid%
	if (ErrorLevel == pid)
		Process Close, %pid%
	
	return xOutput "`n" xError
}

Support Script : WriteInConsole.ahk

Code: Select all

;Support Script for Writing to Console Stdout
#NoTrayIcon
DetectHiddenWindows On
PID = %1%
ControlGetText, TextToStdOut, Edit1, ahk_pid %pid%
FileAppend %TextToStdOut%, *
Process, Close, %PID%
ExitApp
Example: Example.ahk

Code: Select all

/*
Example for directly accessing the archive files
*/
#Include 7-Zip Library.ahk
SetWorkingDir, %A_ScriptDir%
DetectHiddenWindows On

ArchiveFile = %A_ScriptDir%\TestArchive.7z
;;;Change this Path accordingly
7ZCmd = "C:\Program Files\7-Zip\7z.exe"


TextToWrite1 =
(
aaa
bbb
ccc
ddd
eee
)
/*
Add First File to Archive ==> Write Data in it ==> Read Back to Variable
*/
If 7z_WriteFileToArchive(ArchiveFile, "File1.txt", TextToWrite1)
	MsgBox, Data Written
Var1 := 7z_ReadFileFromArchive(ArchiveFile, "File1.txt")
MsgBox, Data from First File:`n %Var1%
If(StrLen(TextToWrite1) + 1 = StrLen(Var1)) ; This is because in console one blank line will be added at the end
	MsgBox, All Ok

TextToWrite2 =
(
fff
ggg
hhh
iii
jjj
kkk
)
/*
Add Another File to Archive ==> Write Data in it ==> Read Back to Variable
*/
If 7z_WriteFileToArchive(ArchiveFile, "File2.txt", TextToWrite2)
	MsgBox, Data Written
Var2 := 7z_ReadFileFromArchive(ArchiveFile, "File2.txt")
MsgBox, Data from Second File:`n %Var2%
If(StrLen(TextToWrite2) + 1 = StrLen(Var2)) ; This is because in console one blank line will be added at the end
	MsgBox, All Ok

ExitApp
Ok Now, about the other trial and errors. Hope someone can find a better solution to these.

Firstly, I tried using Windows native command "echo". It cannot print multi lines. I tried with "&echo." methods. Though the text seems to be in multi-lines, it is not a single stream, 7-Zip only captures either the first line or the last line (depends the method). Tried "Numlock On + Alt + 10" and "Alt+13" methods. They are not working in my Windows 7 x64 system. So, "echo" isn''t suitable. if So, we wouldn't need another supporting script. Also "^" is of no use. It does nothing

In search of a multi-line echo, i found CygWin "echo.exe" does it effortlessly. with -e switch Newline & Carriage return can be written to stream. But the only glitch is that, the text that we want to be written to archive to be processed by replacing all instances of "`n`r" to "\n\r". The real problem is if anywhere in the text(variable) "\n\r" exists, Cygwin echo.exe treats it as new line. So, this doesn't work flawlessly.

I also tried converting multi-line text to hex numbers as a single line parameter, but depends on the input text size, the string manipulations takes time. This works, but slow process.

And I played around with Wscript, and AHk's one of the wonderful functions FileOpen(), FileAppend *, but failed to do it from single script. At this time, I realised, the need of another process that can print the whole text in stdout stream, so managed to get it done in Ahk way. Simple script, few lines and Volla... its a magic

And the next challenge was passing the Variable to this support script in much simplest way. I know Postmessage, sendmessage all works for this. But there was a challenge. if I run the command through wscript(we need the output of the command to identify the success/error), the script will be busy until the command processed. So Post/Send message couldn't help. It works if I simply use Run/RunWait.

The next method, I tried by creating a Invicible GUI with a Edit control, Same thing happened. The GUI hangs, Support script couldn't access the gui.

As a final method, Notepad is a real Savior. It made all of it so easy.

Excuse me for all this lengthy post. I believe someone more knowledgeable can give me a better solution without depending on Notepad and a secondary script.

Thank You.

Return to “Scripts and Functions”

Who is online

Users browsing this forum: No registered users and 23 guests