B4A Library [Lib] Archiver

By courtesy of Djembefola, this library is released as freeware for the benefit of the community. You should send him a big "thank you".

This library provides a basic support for Zip, Tar and Gzip archives (including TarGz). It can compress/uncompress synchronously or asynchronously (one task in the background at a time). This lib doesn't support encryption (but you can use it with encrypted files).

Its use is fairly simple. Examples:
B4X:
Dim Arc As Archiver

Arc.Gzip(File.DirRootExternal, "test2.tar", File.DirRootExternal)
Arc.UnGzip(File.DirRootExternal, "test2.tar.gz", File.DirRootExternal & "/testTARgz2")
Arc.AsyncGzip(File.DirRootExternal & "/media/image", "test.jpg", File.DirRootExternal, "Arc")

Dim m As Map
Try
   m = Arc.ListZipEntries(File.DirRootExternal & "/media/image/Icones", "android-icons.zip")
   For i = 0 To m.Size - 1
      Dim Info(3) As Long
      Info = m.GetValueAt(i)
      Log(m.GetKeyAt(i))
      Log("   Uncompressed size = " & Info(0))
      Log("   Compressed size = " & Info(1))
      Log("   CRC = " & Info(2))
   Next
Catch
   Log(LastException.Message)
End Try

This library is provided as-is and will not be extended to other formats. It uses the JTar library.

Don't forget to credit the authors if you include it in your application:
Frédéric Leneuf-Magaud & Kamran Zafar

v1.11:
I improved the synchronization of asynchronous operations (Async orders can be enqueued now);
The event declarations appear now with Space+Tab in the IDE.*

There's an improved version of this library for Zip files in my ProBundle that supports encryption and decryption.
 

Attachments

  • Archiver v1.11.zip
    26.4 KB · Views: 2,795
Last edited:

Informatix

Expert
Licensed User
Hi thanks for that, I understand but why will progress only work for progressbar1? and not anything else like
B4X:
lable1.text = "Unzipping - " & (Count * 100) / testo

or

B4X:
apm1.Progress = (Count * 100) / testo

it is a real shame that i can only display progress in release mode with progressbar! i will look if i can use a timer and update the circleprogress with the value from progressbar1 and maybe have that hidden!

Thanks

Aidy
You cannot update the views from another thread (because it's not the UI thread). Here are two ways to get rid of this annoyance (to start the demo, you have to touch the screen):
B4X:
Sub Process_Globals
End Sub

Sub Globals
   Dim arc As Archiver
   Dim lbl As Label
   Dim Msg As String
   Dim NumberOfFiles, Progression As Int
   Dim AcSf As AcceleratedSurface
   Dim R As Rect
   Dim Unzipping As Boolean
End Sub

Sub Activity_Create(FirstTime As Boolean)
   lbl.Initialize("")
   lbl.Color = Colors.White
   lbl.TextColor = Colors.Black
   Activity.AddView(lbl, 0, 0, 100%x, 200dip)
   AcSf.Initialize("AcSf", True)
   Activity.AddView(AcSf, 0, 200dip, 100%x, 200dip)
   R.Initialize(0, 50dip, 0, 100dip)
End Sub

Sub Activity_Resume
   AcSf.StartRegularDraw(30)
End Sub

Sub Activity_Pause (UserClosed As Boolean)
   AcSf.StopRegularDraw
End Sub

Sub Activity_Touch (Action As Int, X As Float, Y As Float)
   If Unzipping Then Return
   NumberOfFiles = arc.NumberOfZipEntries(File.DirRootExternal, "archive.zip")
   arc.AsyncUnZip(File.DirRootExternal, "archive.zip", File.DirRootExternal & "/test", "prog")
   Unzipping = True
End Sub

Sub prog_UnZipProgression(Count As Int, FileName As String)
   Msg = Count & " " & FileName
   Progression = Count
   CallSubDelayed(Me, "UpdateLabel")
End Sub

Sub prog_UnZipDone(CompletedWithoutError As Boolean, NbOfFiles As Int)
   Msg = "All done"
   Progression = NbOfFiles
   CallSubDelayed(Me, "UpdateLabel")
End Sub

Sub UpdateLabel
   lbl.Text = Msg
End Sub

Sub AcSf_Draw(AC As AS_Canvas)
   AC.DrawText(Msg, 0, 50dip, Typeface.DEFAULT, 14, Colors.White, AC.ALIGN_LEFT)
   R.Right = 100%x * (Progression/NumberOfFiles)
   AC.DrawRect(R, Colors.Red, True, 0, False)
End Sub
In my demo, I use CallSubDelayed to update the label and I use an accelerated surface to display whatever I want (in this case, I display the same text as the label text and a red progression bar).
 

aidymp

Well-Known Member
Licensed User
You cannot update the views from another thread (because it's not the UI thread). Here are two ways to get rid of this annoyance (to start the demo, you have to touch the screen):
B4X:
Sub Process_Globals
End Sub

Sub Globals
   Dim arc As Archiver
   Dim lbl As Label
   Dim Msg As String
   Dim NumberOfFiles, Progression As Int
   Dim AcSf As AcceleratedSurface
   Dim R As Rect
   Dim Unzipping As Boolean
End Sub

Sub Activity_Create(FirstTime As Boolean)
   lbl.Initialize("")
   lbl.Color = Colors.White
   lbl.TextColor = Colors.Black
   Activity.AddView(lbl, 0, 0, 100%x, 200dip)
   AcSf.Initialize("AcSf", True)
   Activity.AddView(AcSf, 0, 200dip, 100%x, 200dip)
   R.Initialize(0, 50dip, 0, 100dip)
End Sub

Sub Activity_Resume
   AcSf.StartRegularDraw(30)
End Sub

Sub Activity_Pause (UserClosed As Boolean)
   AcSf.StopRegularDraw
End Sub

Sub Activity_Touch (Action As Int, X As Float, Y As Float)
   If Unzipping Then Return
   NumberOfFiles = arc.NumberOfZipEntries(File.DirRootExternal, "archive.zip")
   arc.AsyncUnZip(File.DirRootExternal, "archive.zip", File.DirRootExternal & "/test", "prog")
   Unzipping = True
End Sub

Sub prog_UnZipProgression(Count As Int, FileName As String)
   Msg = Count & " " & FileName
   Progression = Count
   CallSubDelayed(Me, "UpdateLabel")
End Sub

Sub prog_UnZipDone(CompletedWithoutError As Boolean, NbOfFiles As Int)
   Msg = "All done"
   Progression = NbOfFiles
   CallSubDelayed(Me, "UpdateLabel")
End Sub

Sub UpdateLabel
   lbl.Text = Msg
End Sub

Sub AcSf_Draw(AC As AS_Canvas)
   AC.DrawText(Msg, 0, 50dip, Typeface.DEFAULT, 14, Colors.White, AC.ALIGN_LEFT)
   R.Right = 100%x * (Progression/NumberOfFiles)
   AC.DrawRect(R, Colors.Red, True, 0, False)
End Sub
In my demo, I use CallSubDelayed to update the label and I use an accelerated surface to display whatever I want (in this case, I display the same text as the label text and a red progression bar).

Hi, thank you for this I will try it later on, I understand more now. it cannot update the values because it is not running on the same thread! I presume there is something in progressbar that somehow works around this. but you solution looks ideal for me! I was begining to think that this was a major flaw. but it just needed some extra work! thanks once again. This is what i like so much about the language. everyone is so helpful!

Aidy
 

aidymp

Well-Known Member
Licensed User
Just for information using just part of your solution works fine, instead of trying to update the information within the progression sub, using your recommended callsubdelayed and using another sub to do the update also work perfect! So thank you!

B4X:
Sub prog_UnZipProgression(Count As Int, FileName As String)
   Msg = Count & " " & FileName
   Progression = Count
   CallSubDelayed(Me, "Updateprog")
End Sub

Sub Updateprog
' any code in here that you would have normally used in the UnzipProgression sub!
   lbl.Text = Msg
End Sub
 

Informatix

Expert
Licensed User
Just for information using just part of your solution works fine, instead of trying to update the information within the progression sub, using your recommended callsubdelayed and using another sub to do the update also work perfect! So thank you!
Yes, it's what I meant in my post (you have the choice between two solutions). You can also remove Progression = Count if you update only the label.
 

wonder

Expert
Licensed User
Hello Fred,

Is this lib able to unzip a password protected zip file?
 

JTmartins

Active Member
Licensed User
I'm using this. And the zip file is created, however zz_ZipProgression never gets fired.

B4X:
Sub FileListPrepare
    Private ListadeFicheiros As List
    ListadeFicheiros=File.ListFiles(path)
    If ListadeFicheiros.Size=0 Then
        'nada a enviar
    Else
        Private files(ListadeFicheiros.Size) As String
        For f=0 To ListadeFicheiros.Size-1
            files(f)=ListadeFicheiros.Get(f)
        Next
        arc.ZipFiles(path,files,File.DirRootExternal,"teste.zip","zz")
    End If
  
End Sub

Sub zz_ZipProgression(Count As Int, FileName As String)
    Log (Count & "-"& FileName)
End Sub

what am I doing wrong here ?

****EDIT...SOLVED

I need to use the AsyncZipFiles and not the ZipFiles method.
 
Last edited:

mokrokuce

Member
Licensed User
First of all:
Thank you to Djembefola and Informatix.

I have a problem using the library, it creates a zip file that is unreadable. Here is my code:
B4X:
Sub Process_Globals
End Sub

Sub Globals
    Dim cmdZip As Button
    Dim lFiles As Label
End Sub

Sub Activity_Create(FirstTime As Boolean)
    cmdZip.Initialize("cmdZip")
    lFiles.Initialize("")
    cmdZip.Text="Zip"
    Activity.AddView(cmdZip,0,0,100%x,40dip)
    Activity.AddView(lFiles,0,40dip,100%x,100%y-40dip)
End Sub

Sub Activity_Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
End Sub

Sub cmdZip_click
    Dim arc As Archiver
    Dim L As List
    Dim Files(1000) As String
    Dim dir,tmp As String
   
    lFiles.Text=""
    dir=File.DirRootExternal 
    Log(dir)
    l=File.ListFiles(dir)
    For i=0 To l.Size-1
        tmp=l.get(i)
        If tmp.ToLowerCase.Contains("5.jpg") Then
            Log(tmp)
            Files(i)=tmp
            lFiles.Text=lFiles.Text & CRLF & tmp
        End If
    Next
    Try
        arc.AsyncZipFiles (dir,Files,dir,"test.zip","Zipping")
    Catch
        Log(LastException.Message )
    End Try
End Sub

Sub Zipping_ZipProgression(Count As Int,FileName As String)
    Log("Zipping (" & Count & "):" & FileName)
End Sub

I have also uploaded image I am trying to zip and a ZIP file I got.

Any suggestions?
 

Attachments

  • 0000002_branko_brankovič-8-0-5.jpg
    0000002_branko_brankovič-8-0-5.jpg
    65.1 KB · Views: 68
  • test.zip
    56.8 KB · Views: 75

Paulsche

Well-Known Member
Licensed User
I have the problem that my zip file can not be larger than 30MB,
So I can upload it to Google Drive.
Is there a way that can be automatically split into multiple zip files with a maximum size of 30MB?
 

kostefar

Active Member
Licensed User
Dear Archiver Users,

I have this code:

B4X:
If File.Exists (File.DirAssets , "backgrounds.zip") Then
                    unzip.AsyncUnZip(File.DirAssets , "backgrounds.zip",File.DirAssets ,"unzip")
                    File.Delete (File.DirAssets , "backgrounds.zip")
                    End If

Which doesn´t do anything. I had a msgbox popping up before in the code to assure that "backgrounds.zip" indeed is there - it´s in the files of the b4a project, so it will load every time the app is compiled to my emulator, and it´s confirmed to be there.
So nothing is unzipped from this archive which was made with winrar - which can also compress in zip-format.
I also tried to use File.DirDefaultExternal as targetfolder - my original intention, but same result.
I have:

B4X:
Sub Unzip_Unzipdone(comp As Boolean, files As Int)
    Msgbox ("completed " & comp & " files " & files, "")
End Sub

Which gives me: completed false files -1.

Any idea what I´m doing wrong here?

Thanks in advance!
 

Informatix

Expert
Licensed User
Dear Archiver Users,

I have this code:

B4X:
If File.Exists (File.DirAssets , "backgrounds.zip") Then
                    unzip.AsyncUnZip(File.DirAssets , "backgrounds.zip",File.DirAssets ,"unzip")
                    File.Delete (File.DirAssets , "backgrounds.zip")
                    End If

Which doesn´t do anything. I had a msgbox popping up before in the code to assure that "backgrounds.zip" indeed is there - it´s in the files of the b4a project, so it will load every time the app is compiled to my emulator, and it´s confirmed to be there.
So nothing is unzipped from this archive which was made with winrar - which can also compress in zip-format.
I also tried to use File.DirDefaultExternal as targetfolder - my original intention, but same result.
I have:

B4X:
Sub Unzip_Unzipdone(comp As Boolean, files As Int)
    Msgbox ("completed " & comp & " files " & files, "")
End Sub

Which gives me: completed false files -1.

Any idea what I´m doing wrong here?

Thanks in advance!
The reason is pretty simple: you delete the file while the unzipping is in progress. If you want a synchronous execution, use Unzip and not AsyncUnzip.
 

kostefar

Active Member
Licensed User
The reason is pretty simple: you delete the file while the unzipping is in progress. If you want a synchronous execution, use Unzip and not AsyncUnzip.

Thanks, so I first tried removing the file deletion part, but with the same result. Then I changed the unzipping line to:

B4X:
unzip.Unzip(File.DirAssets , "backgrounds.zip",File.DirAssets ,"unzip")

and now I get:

B4X:
java.io.IOException: java.io.FileNotFoundException: /AssetsDir/backgrounds.zip: open failed: ENOENT (No such file or directory)

... even if the unzipping is only launched upon file.exists...

Also tried with a simple archive of 2 kb with only one file, very short filename, no directories and zipped using 7zip (with classic zip algorhitm) but same result.

So, what could be the problem?
 
Last edited:

Informatix

Expert
Licensed User
Thanks, so I first tried removing the file deletion part, but with the same result. Then I changed the unzipping line to:

B4X:
unzip.Unzip(File.DirAssets , "backgrounds.zip",File.DirAssets ,"unzip")

and now I get:

B4X:
java.io.IOException: java.io.FileNotFoundException: /AssetsDir/backgrounds.zip: open failed: ENOENT (No such file or directory)

... even if the unzipping is only launched upon file.exists...

Also tried with a simple archive of 2 kb with only one file, very short filename, no directories and zipped using 7zip (with classic zip algorhitm) but same result.

So, what could be the problem?
I did not pay attention to the unzip parameters. There are two problems: you try to unzip from the assets dir, which is not allowed (you have to copy the file in a normal folder), and you want to put the unzipped files in the assets dir, which is read-only.
 

kostefar

Active Member
Licensed User
I did not pay attention to the unzip parameters. There are two problems: you try to unzip from the assets dir, which is not allowed (you have to copy the file in a normal folder), and you want to put the unzipped files in the assets dir, which is read-only.

Thanks, now it works!

B4X:
File.Copy (File.DirAssets , "1.zip",File.DirDefaultExternal & "/" & usernametmp,"1.zip")
unzip.Unzip(File.DirDefaultExternal & "/" & usernametmp , "1.zip",File.DirDefaultExternal & "/" & usernametmp ,"unzip")
 

wonder

Expert
Licensed User
Hi!

This may be a dumb question but here it goes.

For my Python library, on the Java side, I need to perform the following task:
- Unzip a zip file in 'DirAssets' to 'DirDefaultInternal'
- Unzip the copied zip file into its current location
- Delete the zip file

Would it be possible to use this library from the Java side?
 

Informatix

Expert
Licensed User
Hi!

This may be a dumb question but here it goes.

For my Python library, on the Java side, I need to perform the following task:
- Unzip a zip file in 'DirAssets' to 'DirDefaultInternal'
- Unzip the copied zip file into its current location
- Delete the zip file

Would it be possible to use this library from the Java side?
The purpose of this library is to unzip files, so I'm not sure to understand what's the question.
 

wonder

Expert
Licensed User
I'm writing a library (Java) which assumes the existence of a zip file named 'mylib.zip' in 'DirAssets'.

For a correct initialization, the end-user (B4A developer) has to copy the file into DirInternal/DirExternal and unzip it.
I'd like this step to be automated on the Java side, so that all the end-user has to do is call 'myclass.Initialize' without worried about copying and unzipping stuff.

Hence my need to have a Java solution that copies and unzips a file.
 

Informatix

Expert
Licensed User
I'm writing a library (Java) which assumes the existence of a zip file named 'mylib.zip' in 'DirAssets'.

For a correct initialization, the end-user (B4A developer) has to copy the file into DirInternal/DirExternal and unzip it.
I'd like this step to be automated on the Java side, so that all the end-user has to do is call 'myclass.Initialize' without worried about copying and unzipping stuff.

Hence my need to have a Java solution that copies and unzips a file.
In this case, you should use the java.util.zip package to unzip your file:
https://developer.android.com/reference/java/util/zip/package-summary.html
Example from the Archiver code:
B4X:
    private synchronized void internalUnZip(ZipInputStream zis, String destFolder) throws IOException {
        BufferedOutputStream dest = null;

        ZipEntry entry;
        while ((entry = zis.getNextEntry()) != null) {
            if (entry.isDirectory()) {
                new File(getFileLocation(destFolder, entry.getName())).mkdirs();
                continue;
            }
            else {
                int di = entry.getName().lastIndexOf('/');
                if (di != -1) {
                    new File(getFileLocation(destFolder, entry.getName().substring(0, di))).mkdirs();
                }
            }
            FileOutputStream fos = new FileOutputStream(getFileLocation(destFolder, entry.getName()));
            dest = new BufferedOutputStream(fos);

            int count;
            byte data[] = new byte[Buffer];
            while ((count = zis.read(data)) != -1) {
                dest.write(data, 0, count);
            }

            dest.flush();
            dest.close();
        }
    }
 
Top