B4J Code Snippet [B4X] Unzip single entry from a zip file / ZipToMap / MapToZip

B4A + B4J code. Reads the data of a single entry.
B4X:
'Depends on JavaObject. Returns 0 bytes array if entry not found.
Private Sub UnzipEntry(ZipPath As String, Entry As String) As Byte()
    Dim result() As Byte
    Dim ZipFile As JavaObject
    ZipFile.InitializeNewInstance("java.util.zip.ZipFile", Array(ZipPath))
    Dim ZipEntry As JavaObject = ZipFile.RunMethod("getEntry", Array(Entry))
    If NotInitialized(ZipEntry) Then Return result
    result = Bit.InputStreamToBytes(ZipFile.RunMethod("getInputStream", Array(ZipEntry)))
    ZipFile.RunMethod("close", Null)
    Return result
End Sub

Usage example:
B4X:
Sub AppStart (Args() As String)
    Dim b() As Byte = UnzipEntry("C:\Users\H\Documents\B4X\XUI Views.b4xlib", "manifest.txt")
    If b.Length = 0 Then
        Log("entry not found")
    Else
        Dim s As String = BytesToString(b, 0, b.Length, "utf8")
        Log(s)
    End If
End Sub

Getting file from subfolder:
B4X:
Dim b() As Byte = UnzipEntry("C:\Users\H\Documents\B4X\XUI Views.b4xlib", "B4J/B4JTextFlow.bas")
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
And if you want to read the complete zip into a Map with names as keys and the files data as array of bytes:
B4X:
Sub AppStart (Args() As String)
    Dim files As Map = ZipToMap("C:\Users\H\Documents\B4X\XUI Views.b4xlib")
    Dim b() As Byte = files.Get("SwiftButton.bas")
    Log(BytesToString(b, 0, b.Length, "utf8"))
End Sub

Private Sub ZipToMap (ZipPath As String) As Map
    Dim result As Map
    result.Initialize
    Dim ZipFile As JavaObject
    ZipFile.InitializeNewInstance("java.util.zip.ZipFile", Array(ZipPath))
    Dim enumeration As JavaObject = ZipFile.RunMethod("entries", Null)
    Do While enumeration.RunMethod("hasMoreElements", Null).As(Boolean)
        Dim ZipEntry As JavaObject = enumeration.RunMethod("nextElement", Null)
        Dim Name As String = ZipEntry.RunMethod("getName", Null)
        If Name.EndsWith("/") Then Continue 'ignore directory entries
        'you can add name filters here
        result.Put(Name, Bit.InputStreamToBytes(ZipFile.RunMethod("getInputStream", Array(ZipEntry))))
    Loop
    ZipFile.RunMethod("close", Null)
    Return result
End Sub
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
And if you want to create a zip file: MapToZip

Input: map with the entries names as strings and the files data as array of bytes.

B4X:
Public Sub MapToZip (NamesAndBytes As Map, ZipPath As String)
    Dim out As OutputStream = File.OpenOutput(ZipPath, "", False)
    Dim zout As JavaObject
    zout.InitializeNewInstance("java.util.zip.ZipOutputStream", Array(out))
    For Each name As String In NamesAndBytes.Keys
        Dim bytes() As Byte = NamesAndBytes.Get(name)
        Dim ZipEntry As JavaObject
        ZipEntry.InitializeNewInstance("java.util.zip.ZipEntry", Array(name))
        zout.RunMethod("putNextEntry", Array(ZipEntry))
        zout.RunMethod("write", Array(bytes, 0, bytes.Length))
        zout.RunMethod("closeEntry", Null)
    Next
    zout.RunMethod("close", Null)
    out.Close
End Sub

Usage example:
B4X:
Dim NamesAndBytes As Map
NamesAndBytes.Initialize
NamesAndBytes.Put("this is the first file.txt", "this is the content".GetBytes("utf8"))
NamesAndBytes.Put("this is the folder/and this is the second file.txt", "aaa".GetBytes("utf8"))
NamesAndBytes.Put("this is the folder/logo.png", File.ReadBytes(File.DirAssets, "logo.png"))
MapToZip(NamesAndBytes, "C:\Users\H\Downloads\1.zip")
 
Top