B4J Question ArchiverPlusZip skips files on compression

johnmie

Active Member
Licensed User
Longtime User
Hi,
I am using the ArchiverPlusZip Library in my B4J project with success (thank you, Frédéric) most of the time, but sometimes an Arc.AddFileToZip just does not add the file to the zip.
There are normally 8-12 image files of various length (in a for...next loop) that have to be added which could be in any of 3 directories like this

B4X:
    Dim ArchiveFolder As String = Q.lastFolder&"\"&zipname
    Arc.ZipExecutionMode = Arc.ZIP_EXECMODE_ASYNCHRONOUS
    Arc.ZipCompression = True
    Arc.ZipCompressionLevel = 8  'tried with level 4: no difference
    for ...
...else if File.Exists(Q.lastFolder,B) Then
     Log("3 zip adding image "&B&"  from  "& Q.lastFolder) 'where B is the file name
     Arc.AddFileToZip(Q.lastFolder&"\"&B,ArchiveFolder,"Archiver")
 End If
 Do While Arc.ZipResultCode = Arc.ZIP_RESULT_WORKING
         Sleep(0) 'as found in your sample code - tried without sleep and with sleep(500): no difference
loop
next
  Loop

And it is never the same 2 or 3 files that are skipped.
I've read somewhere that you'd have to put it in a SUB, but can't remember where I saw this, can't figure out how and could not find an amateur-friendly example.

Can anyone please help me resolve my dilemma?
Thank you very much in advance,
john m.
 

behnam_tr

Active Member
Licensed User
Longtime User
test this code
you can creat list of all files befor use arc.AddFilesToZip

B4X:
Sub Button1_Click
   
   
    Dim arc As ArchiverPlusZip
    arc.ZipExecutionMode = arc.ZIP_EXECMODE_ASYNCHRONOUS
    arc.ZipCompression = True
    arc.ZipCompressionLevel = 8

    'Encrypt zip File
    Dim Mypassword As String = "12345678"
    Dim Const Password() As Byte = Mypassword.GetBytes("UTF-8")
    arc.EncryptZipWithArray(arc.ZIP_ENC_METHOD_STANDARD, -1, Password)
               
    Dim zipname As String = "test.zip"
   
    File.Delete(File.DirApp,zipname) 'you need to delete zip file if exist
   

    Dim myfilespath As String = File.DirApp&"/myfiles"

    Dim l As List= File.ListFiles(myfilespath)
   
    arc.AddFilesToZip(l,File.DirApp&"\"&zipname,"Archiver")
   
   
    Sleep(500)
    fx.ShowExternalDocument(File.GetUri(File.DirApp,"test.zip"))


End Sub

Private Sub Archiver_ZipResult(Result As Int, ErrorMsg As String)
   
   
    Log(Result)
    Log(ErrorMsg)
   
End Sub
 
Upvote 0

behnam_tr

Active Member
Licensed User
Longtime User
i find a Solution

add sleep(500) or more after arc.AddFileToZip(..) depends on file size

B4X:
Dim myfilespath As String = File.DirApp&"\myfiles"
 
    Dim l As List= File.ListFiles(myfilespath)
 
    For i=0 To l.Size-1
    
        Log(myfilespath&"\"&l.Get(i))
        Dim filepath As String = myfilespath&"\"&l.Get(i)
    
        arc.AddFileToZip(filepath,File.DirApp&"\"&zipname,"Archiver")
        Sleep(500)
    Next

or use waitFor


B4X:
 For i=0 To l.Size-1

     

        Log(myfilespath&"\"&l.Get(i))

        Dim filepath As String = myfilespath&"\"&l.Get(i)

     

        arc.AddFileToZip(filepath,File.DirApp&"\"&zipname,"Archiver")

        Wait For Archiver_ZipResult(Result As Int, ErrorMsg As String)

        Log(Result)

        Log(ErrorMsg)



    Next
 
Upvote 0

MicroDrie

Well-Known Member
Licensed User
If you search this forum you will come across a comment somewhere in the posts by Erel that Archiver_ZipResult threats will not be handled properly if you do not use CallSubDelayed. Based on his advice:

Zip succes handling:
Sub Archiver_ZipResult(Result As Int, ErrorMsg As String)
    Select Result
        Case Arc.ZIP_RESULT_SUCCESS
            CallSubDelayed(Me,"ZipMsg")
        Case Else
            CallSubDelayed(Me,"ZipError")
    End Select
End Sub

Private Sub ZipMsg
    Log("Zip succes")
    xui.Msgbox2Async("Zipper done.", "Zip result", "Ok", "", "", Null)
    Wait For Msgbox_Result (Result As Int)
End Sub

Sub ZipError(ErrorStr As String)
    Dim ErrStr As String = $"Zip error: ${ErrorStr}"$
    Log(ErrStr    )
    xui.Msgbox2Async("Zipper error.", ErrStr, "Ok", "", "",Null)
    Wait For Msgbox_Result (Result As Int)
End Sub
 
Upvote 0

johnmie

Active Member
Licensed User
Longtime User
My cordial thanks to Iran and the Netherlands.
At first I liked behnam_tr's arc.AddFilesToZip idea and tried it after copying all files to the same folder and generate a new list.
This did indeed very rapidly build a zip-file without error, but the zip-file had a length of zero.
Then I tried in addition to add all files in a for-next loop, without sleep(500) but using Frédéric's Do While Arc.ZipResultCode = Arc.ZIP_RESULT_WORKING
And this double take seems to work perfectly (in 1.33 seconds for one text file and 16 small *.png files).

Maybe micro3's approach would possibly be simpler and/or faster. I'll try the working code tomorrow again a few times. If I then still get any errors, I'll happily follow micro3's suggestion. I had actually seen Erel's post you mentioned, but have never been very successful with CallSubDelayed in B4J.

Thank you for your help,
john m.
 
Upvote 0

MicroDrie

Well-Known Member
Licensed User
I had actually seen Erel's post you mentioned, but have never been very successful with CallSubDelayed in B4J.
I came to the CallSubDelayed solution because I had a lot of problems with the zip application. While debugging step by step I noticed the strangest program steps explainable by Erel's reference to and stated reason for using the CallSubDelayed routine. I haven't seen that during step by step debugging since I've been using Erel's CallSubDelayed solution.
 
Upvote 0

johnmie

Active Member
Licensed User
Longtime User
to micro3:
what seemed to work wonderfully yesterday still skips some files sometimes. At what point would I inset a call to your Archiver_ZipResult in my B4J code?
B4X:
    For i = 0 To oFiles.Size -1
        Dim filepath As String = Q.tempPath&"\"&oFiles.Get(i)
            Arc.AddFileToZip(filepath,targetDir&"\"&zipname,"Archiver")
            Do While Arc.ZipResultCode = Arc.ZIP_RESULT_WORKING
                Sleep(0)
            Loop
    Next
 
Upvote 0

MicroDrie

Well-Known Member
Licensed User
what seemed to work wonderfully yesterday still skips some files sometimes.
OK, I recognize that as the difference between solving a symptom for a certain circumstance or actually solving a problem. How to deal with events was not my solution, but Erel's. In this case he gave it with an explanation, which is indeed the solution for my problem.

I love simple ways, so why don't we do it the simplest way with the following one-liner?
Add directory to zip archive with AddFoldertoZip:
Arc.AddFolderToZip(Q.tempPath,targetDir&"\"&zipname,"Archiver")
This on-liner is the replacement for your 7 lines of code.
At what point would I inset a call to your Archiver_ZipResult in my B4J code?
Next thing what we have to do is to add the subroutines I give in post 4. I put those sub routines direct behind the the sub routine which contain the Arc.AddFolderToZip program code. But that's a matter of convenience to keep related code together so that that I can those subroutines collapse with #region if everything works properly and copy that #region code if I want to reuse the program code.

And speaking of reuse and Erel, I also follow Erel's advice to use xui.SetDataFolder and xui.DefaultFolder as much as possible to increase simple code interchangeability between my B4A and B4J programs.
 
Upvote 0

johnmie

Active Member
Licensed User
Longtime User
This was actually the very first thing I did, but it had the disadvantage that it A) created a zip with a folder structure and B) included all files in the folder, even those that were no longer required.

This is not a problem for me during development, but might be difficult to manage for other users of my app. I'll keep trying and include workarounds for A) and B)
 
Upvote 0

MicroDrie

Well-Known Member
Licensed User
In that case remove this code:
Remove this code:
            Do While Arc.ZipResultCode = Arc.ZIP_RESULT_WORKING
                Sleep(0)
            Loop
and add the Archive_subroutines from post 4
 
Upvote 0

johnmie

Active Member
Licensed User
Longtime User
Thank you micro3.
Now it seems to work perfectly using a combination of your, Erel's and Frédéric's codes
B4X:
    For i = 0 To oFiles.Size -1 'one script file (text) and 13 pictures
        Dim filepath As String = Q.tempPath&"\"&oFiles.Get(i)
            Arc.AddFileToZip(filepath,targetDir&"\"&zipname,"Archiver")
            Do While Arc.ZipResultCode = Arc.ZIP_RESULT_WORKING
                Sleep(0)
            Loop
    Next

I kept the do while... and added your three subs but replaced the xui.Msgbox2Async with logs

and this is the happy result (which includes a lot of Klaus' stuff):
 

Attachments

  • VCIL_1.png
    VCIL_1.png
    19.8 KB · Views: 120
Upvote 0
Top