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
}
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
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
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.