How to extract a file in a zip archive (without using OS specific tools)?

I am trying to extract a file from a zip archive using ZipFile.jl, but I don’t know how to write it back to disk:

using ZipFile
zarchive = ZipFile.Reader("myarchive.zip")
myf = zarchive.files[1]
out =  open(myf.name,"w")
write(out,myf) # error
close(out)
close(zarchive)

This is the solution I found. It works in my case (shapefiles, a zipfile wit ha single subdirectory level) but I don’t think it is very “solid” (e.g. may not work with other kind of binary files, as I am using String as a temporary medium…):

zarchive = ZipFile.Reader("myarchive.zip")

for f in zarchive.files
    println(f.name)
    fullFilePath = joinpath(rootDir,dataFolder,f.name)
    if endswith(f.name,"/")
        mkdir(fullFilePath)
    else
        out =  open(fullFilePath,"w")
        write(out,read(f,String))
        close(out) 
    end
end

close(zarchive)

Maybe you can use Vector{UInt8} instead of String? It should give more generic solution

If you prefer to write less, you can shorten that to

write(fullFilePath, read(f, String))

Without having tested I suspect that you can also shorten read(f, String) to read(f) for this use case.

2 Likes

Thank you all.

I ended up writing the following function:

unzip(file,exdir="")

Unzip a zipped archive using ZipFile

Arguments

  • file: a zip archive to unzip and extract (absolure or relative path)
  • exdir="": an optional directory to specify the root of the folder where to extract the archive (absolute or relative).

Notes:

  • The function doesn’t perform a check to see if all the zipped files have a common root.

Examples

julia> unzip("myarchive.zip",exdir="mydata")
function unzip(file,exdir="")
    fileFullPath = isabspath(file) ?  file : joinpath(pwd(),file)
    basePath = dirname(fileFullPath)
    outPath = (exdir == "" ? basePath : (isabspath(exdir) ? exdir : joinpath(pwd(),exdir)))
    isdir(outPath) ? "" : mkdir(outPath)
    zarchive = ZipFile.Reader(fileFullPath)
    for f in zarchive.files
        fullFilePath = joinpath(outPath,f.name)
        if (endswith(f.name,"/") || endswith(f.name,"\\"))
            mkdir(fullFilePath)
        else
            write(fullFilePath, read(f))
        end
    end
    close(zarchive)
end

If one is interested, I added it to my own repository of utility functions (https://github.com/sylvaticus/LAJuliaUtils.jl)

1 Like