Reading, listing and writing TAR files
version: >= 20220508
It’s possible to directly read, list or write TAR (or tar gzipped files) directly from OpenAF. This allows OpenAF scripts not only to work with ZIP files but also tar/tar.gz files.
Writing
Let’s start by writing a simple tar file based on a Java source-code folder (e.g. “src”) with multiple levels of folders:
ow.loadFormat()
print("Creating mytar.tgz:")
io.writeFileTARStream("mytar.tgz", true, writer => {
// Listing all files that end in .java from the sub-folder src
$from( listFilesRecursive("src") )
.ends("filename", ".java")
.select(r => {
// Remove src/ prefix from the path
var targetFilePath = r.filepath.replace(/^src\//, "")
// Add bytes abbreviation
r.bytesAbb = ow.format.toBytesAbbreviation(r.size)
tprint(" writing {{filepath}} ({{bytesAbb}})", r)
// Writing a file to the tgz file
writer(targetFilePath, io.readFileStream(r.filepath))
})
})
The function io.writeFileTARStream receives three arguments: a target filename (or Java stream), a boolean to indicate if it’s gzipped or not and a function that provides a writer function. This writer function should be called as many times as files you want to add to your tgz file. It’s arguments are: filePathOnTheTarFile, inputJavaStreamForAFile.
The result of running the previous code will be similar to this:
$ tar tzf mytar.tgz
openaf/JAnsiRender.java
openaf/OAFdCL.java
openaf/CompileJS2Java.java
openaf/OAFEngineFactory.java
openaf/plugins/SSH.java
openaf/plugins/HTTP.java
openaf/plugins/ZIP.java
[...]
Notice that despite the files being located in src/openaf/* and src/openaf/plugins/* what matters is the targetFilePath you provide to the writer function.
Listing
To list you just need to use the function io.listFilesTAR:
> $from( io.listFilesTAR("mytar.tgz") )
.less("size", 1024)
.select({ filepath: "", size: -1 })
╭ [0] ╭ filepath: openaf/jline/OpenAFArgumentDelimiter.java
│ ╰ size : 552
├ [1] ╭ filepath: openaf/core/AF.java
│ ╰ size : 212
├ [2] ╭ filepath: org/json/JSONException.java
│ ╰ size : 709
├ [3] ╭ filepath: org/json/JSONString.java
│ ╰ size : 740
╰ [4] ╭ filepath: com/jamesmurty/utils/XMLBuilderRuntimeException.java
╰ size : 526
Reading
To read you can use the function io.readFileTARStream:
ow.loadFormat()
var targetFolder = "/tmp/myTar"
var source = "mytar.tgz"
print("Expanding " + source + "...")
$from( io.listFilesTAR(source) )
.less("size", 1024)
.select(r => {
io.readFileTARStream(source, r.filepath, true, iStream => {
// Determines the complete path
var parentDir = targetFolder + "/" + r.filepath.substr(0, r.filepath.lastIndexOf("/"))
io.mkdir(parentDir) // Ensure folder is created or exists
// Add bytes abbreviation
r.bytesAbb = ow.format.toBytesAbbreviation(r.size)
tprint(" writing {{filepath}} ({{bytesAbb}})", r)
ioStreamCopy(io.writeFileStream(parentDir + "/" + r.filename), iStream)
})
})
If you need just the contents of file you can quickly do it using io.readFileTARBytes:
var fileContents = af.fromBytes2String( io.readFileTARBytes("mytar.tgz", "openaf/core/AF.java", true) )
print("The file has #" + fileContents.split("\n").length + " lines.")