Unable to zip symlinks that link to directories Zip4j - java

With Zip4j, I've been able to successfully zip symlinks that link to regular files correctly. However, symlinks that link to directories aren't working for me. Keep in mind that I'm trying to mirror the following shell command from Info-ZIP: zip -yr someDirectory.
Toy example:
I created one directory with a symlink to it and a regular file with a symlink to it like so:
$ mkdir tmp
$ cd tmp
$ mkdir a; ln -s a b; touch c; ln -s c d
$ cd ..
$ tree tmp
tmp
├── a
├── b -> a
├── c
└── d -> c
Ideally what would happen is the following:
$ zip -yr tmp.zip tmp
$ unzip tmp.zip -d newtmp
Archive: tmp.zip
creating: newtmp/tmp/
creating: newtmp/tmp/a/
extracting: newtmp/tmp/c
linking: newtmp/tmp/d -> c
linking: newtmp/tmp/b -> a
finishing deferred symbolic links:
newtmp/tmp/d -> c
newtmp/tmp/b -> a
$ tree newtmp
newtmp
└── tmp
├── a
├── b -> a
├── c
└── d -> c
I then attempted to use Zip4j to zip these files.
For symlinks, I call setSymbolicLinkAction with INCLUDE_LINK_ONLY and manually set CompressionLevel.NO_COMPRESSION and CompressionMethod.STORE. I also set the filename for directories such that they are appended with a /.
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.CompressionLevel;
import net.lingala.zip4j.model.enums.CompressionMethod;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
public class ZipTest {
public static void main(String[] args) throws IOException {
try (ZipFile zipFile = new ZipFile("test.zip");
Stream<Path> paths = Files.walk(Paths.get("tmp"))) {
paths.forEach(path -> {
ZipParameters zp = new ZipParameters();
if ((!Files.isSymbolicLink(path)) && Files.isDirectory(path)) {
zp.setFileNameInZip(path + "/");
} else {
zp.setFileNameInZip(path.toString());
}
if (Files.isSymbolicLink(path)) {
zp.setSymbolicLinkAction(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_ONLY);
zp.setCompressionLevel(CompressionLevel.NO_COMPRESSION);
zp.setCompressionMethod(CompressionMethod.STORE);
}
try {
zipFile.addFile(path.toFile(), zp);
} catch (ZipException e) {
throw new RuntimeException(e);
}
});
}
}
}
Unzipping output:
$ unzip test.zip -d test
Archive: test.zip
creating: test/tmp/
creating: test/tmp/a/
extracting: test/tmp/c
linking: test/tmp/d -> c
extracting: test/tmp/b
finishing deferred symbolic links:
test/tmp/d -> c
That didn't work. The symlink b to directory a did not stay a symlink. I've also tried:
allowing symlinks identified as directories to have / in their file name.
zip parameters without setting compression
calling the addFolder API on just the input directory
and nothing has worked so far.

This is now a known bug in Zip4j. See https://github.com/srikanth-lingala/zip4j/issues/486.

Related

Processing.org 3 and loading Java properties file?

I am not all that knowledgeable in Java, and I'm trying to use some Java in a Processing.org 3 project. I have managed to reconstruct the problem in a small Processing example project called testprocjavapath - and I am posting a bash script (called testProcJavaLoadpath.sh) that reconstructs the example project files at the end of this post, and runs the project once. The testprocjavapath project files look like this:
~/sketchbook/testprocjavapath
├── testprocjavapath.pde
├── myprops.properties
└── MyJavaClass.java
When running the script, I get this:
$ bash testProcJavaLoadpath.sh
...
There was an exception myprops.properties: java.lang.NullPointerException : null
The properties file content is 'null';
Finished.
Debugging in Processing 3 IDE GUI, this error occurs on exactly the line properties.load(in);:
... because the line InputStream in = MyJavaClass.class.getResourceAsStream(inFileName); failed, and as a result, in is a null pointer.
That much I understand - what I don't understand is this: how do I load a, say, .properties text file, in the same directory as the .pde Processing sketch file and the .java file (that is, this particular sketch folder)?
As far as I gather the Java getResourceAsStream() actually is used to load from a Java application packed as a .jar file - so can it work for reading files from hard disk, that are not yet packed as .jar files?
If not - I have also tried to do:
InputStream in = new FileInputStream( new File(PROPERTIES_FILENAME));
... but this didn't work either (in is again null).
So, what command can I use in the .java file, to load the myprops.properties file? And if I should end up packing the whole Processing app as a .jar file (not sure if Processing can do this, haven't looked it up yet), would I have to change that command?
Here is the testProcJavaLoadpath.sh file (make sure you change PROCBINPATH to your Processing install path):
PROCSKETCHDIR="~/sketchbook"
PROCSKETCHDIR="${PROCSKETCHDIR/#\~/$HOME}" # expand home dir ~
echo "$PROCSKETCHDIR"
PROCBINPATH="/PATH/TO/processing-3.3.6" # path/location of Processing executable `processing-java`
MYSKETCH="testprocjavapath"
MYSKETCHDIR="$PROCSKETCHDIR/$MYSKETCH"
# reconstruct folder:
rm -rfv "$MYSKETCHDIR"
mkdir -v "$MYSKETCHDIR"
echo "generating $MYSKETCHDIR/$MYSKETCH.pde"
cat > "$MYSKETCHDIR/$MYSKETCH.pde" <<'EOF'
void setup() {
size(640, 360); // Size should be the first statement
MyJavaClass myjc = new MyJavaClass();
String thefilecontents = myjc.GetPropsFileContent();
System.out.format("The properties file content is '%s';%n", thefilecontents);
}
EOF
echo "generating $MYSKETCHDIR/myprops.properties"
cat > "$MYSKETCHDIR/myprops.properties" <<'EOF'
teststr=HelloWorld
EOF
echo "generating $MYSKETCHDIR/MyJavaClass.java"
cat > "$MYSKETCHDIR/MyJavaClass.java" <<'EOF'
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.io.FileInputStream;
import java.io.File;
import java.io.ByteArrayOutputStream;
public class MyJavaClass {
private static final String PROPERTIES_FILENAME = "myprops.properties";
/**
* add a constructor
*/
public static void MyJavaClass() {
}
public static String GetPropsFileContent() {
String myret = null;
myret = readgetFileContent(PROPERTIES_FILENAME);
return myret;
}
public static String readgetFileContent(String inFileName) {
String result = null;
Properties properties = new Properties();
try {
InputStream in = MyJavaClass.class.getResourceAsStream(inFileName);
properties.load(in);
ByteArrayOutputStream resultbaos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) != -1) {
resultbaos.write(buffer, 0, length);
}
result = resultbaos.toString();
} catch (IOException e) {
System.err.println("There was an error reading " + inFileName + ": " + e.getCause()
+ " : " + e.getMessage());
} catch (Exception e) {
System.err.println("There was an exception " + inFileName + ": " + e
+ " : " + e.getMessage());
}
return result;
}
}
EOF
# run once:
"$PROCBINPATH"/processing-java --sketch="$MYSKETCHDIR" --run
Ok, I managed to get somewhere - but I'd still like a more qualified answer.
First of all, it turns out, Processing as such expect files to be read (like myprops.properties in the OP example), to be stored in a data subfolder of the sketch folder:
https://processing.org/tutorials/data/
And just as with image files, these text files should be placed in the sketch’s “data” directory in order for them to be recognized by the Processing sketch.
So far so good - and indeed, inside the Processing .pde sketch, we can use (say) loadStrings("myprops.properties");, and the file at data/myprops.properties will be read. However, I don't need to read the file there - I need to read it in the supporting .java class.
Now, when you run the Processing patch (either from IDE, or from the command line), what happens is that Processing copies the source files from the sketch folder, inside a temporary folder in the /tmp folder (at least on Linux); here's how that file structure looks like:
/tmp/testprocjavapath9179591342074530534temp/
├── MyJavaClass.class
├── source
│   ├── MyJavaClass.java
│   └── testprocjavapath.java
└── testprocjavapath.class
Notice that we have .java source files, and .class "compiled" files, but there is no data subfolder or myprops.properties file anywhere!
Now, notice also that what used to be testprocjavapath.pde in the source sketch folder, becomes testprocjavapath.java (and corresponding .class) in the temporary folder; notice that testprocjavapath.java defines:
public class testprocjavapath extends PApplet {
Now, the loadStrings is actually a method of the PApplet class; so if we read through it a bit:
https://github.com/processing/processing/blob/master/core/src/processing/core/PApplet.java
dataPath(String where): .... The data path is handled differently on each platform, and should not be considered a location to write files. It should also not be assumed that this location can be read from or listed. ... Libraries should use createInput() to get an InputStream or createOutput() to get an OutputStream. sketchPath() can be used to get a location relative to the sketch. Again, do not use this to get relative locations of files. ...
... we can see a method dataPath, however it's usage is not recommended. On the other hand, there is a method sketchPath - however, this method will only return the correct path (i.e. a sketch in ~/sketchbook in this example) if called from the top-level .pde file! If you try to have the class in the .java file defined as extends PApplet, and then call sketchPath from there - it will simply return the current working directory!
So the solution for now is:
Have the .java class accept an input argument in the constructor, which will be used to record the proper sketch path: public MyJavaClass(String inSketchPath) {
Then, have the sketchPath() passed to the .java class instance during instantiation in the .pde file: MyJavaClass myjc = new MyJavaClass( sketchPath() );
Finally, use the passed sketch path inside the .java class, to calculate the absolute path of the .properties file, and then load it with new FileInputStream( new File(theFilePath) ); (not with getResourceAsStream!)
Below a changed testProcJavaLoadpath.sh is pasted, that has these modifications, and in principle, works - this is the terminal output:
$ bash testProcJavaLoadpath.sh
...
Sketch first lines: 'teststr=HelloWorld';
Sketch dataFile: '~/sketchbook/testprocjavapath/data/myprops.properties';
Sketch sketchPath: '~/sketchbook/testprocjavapath';
:: mySketchPath: '~/sketchbook/testprocjavapath'
:: The URL is 'file:/tmp/testprocjavapath4709659129218148940temp/';
:: name: MyJavaClass.class
:: resourcePath: file:/tmp/testprocjavapath4709659129218148940temp/MyJavaClass.class
:: theFilePath: '~/sketchbook/testprocjavapath/data/myprops.properties'
:: properties: key 'teststr' => value 'HelloWorld'
The properties file content is 'teststr=HelloWorld
';
... however, I imagine if I should want to pack this code in a .jar or executable application/file, this approach would likely fail - which is why I'd still like a more qualified answer.
The changed testProcJavaLoadpath.sh is this:
PROCSKETCHDIR="~/sketchbook"
PROCSKETCHDIR="${PROCSKETCHDIR/#\~/$HOME}" # expand home dir ~
echo "$PROCSKETCHDIR"
PROCBINPATH="/PATH/TO/processing-3.3.6" # path/location of Processing executable `processing-java`
MYSKETCH="testprocjavapath"
MYSKETCHDIR="$PROCSKETCHDIR/$MYSKETCH"
# reconstruct folder:
rm -rfv "$MYSKETCHDIR"
mkdir -v "$MYSKETCHDIR"
# https://processing.org/tutorials/data/
# "And just as with image files, these text files should be placed in the sketch’s “data” directory in order for them to be recognized by the Processing sketch."
# processing.core.PApplet.loadStrings - https://processing.github.io/processing-javadocs/core/
# https://github.com/processing/processing/blob/master/core/src/processing/core/PApplet.java
# "dataPath(String where): The data path is handled differently on each platform, and should not be considered a location to write files. It should also not be assumed that this location can be read from or listed. ... Libraries should use createInput() to get an InputStream or createOutput() to get an OutputStream. sketchPath() can be used to get a location relative to the sketch. Again, <b>do not</b> use this to get relative locations of files."
echo "generating $MYSKETCHDIR/$MYSKETCH.pde"
cat > "$MYSKETCHDIR/$MYSKETCH.pde" <<'EOF'
void setup() {
size(640, 360); // Size should be the first statement
String[] lines = loadStrings("myprops.properties"); // reads from data/myprops.properties
System.out.format("Sketch first lines: '%s';%n", lines[0]);
System.out.format("Sketch dataFile: '%s';%n", dataFile("myprops.properties")); // ~/sketchbook/testprocjavapath/data/myprops.properties
System.out.format("Sketch sketchPath: '%s';%n", sketchPath()); // ~/sketchbook/testprocjavapath
MyJavaClass myjc = new MyJavaClass( sketchPath() );
String thefilecontents = myjc.GetPropsFileContent();
System.out.format("The properties file content is '%s';%n", thefilecontents);
}
EOF
mkdir -v "$MYSKETCHDIR/data"
echo "generating $MYSKETCHDIR/data/myprops.properties"
cat > "$MYSKETCHDIR/data/myprops.properties" <<'EOF'
teststr=HelloWorld
EOF
echo "generating $MYSKETCHDIR/MyJavaClass.java"
cat > "$MYSKETCHDIR/MyJavaClass.java" <<'EOF'
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream; // "InputStream is by definition not seekable."
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.io.FileInputStream; // is seekable
import java.io.File;
import java.io.ByteArrayOutputStream;
import java.net.URL;
//import processing.core.*;
import java.nio.file.Path;
import java.nio.file.Paths;
public class MyJavaClass {
private static final String PROPERTIES_FILENAME = "myprops.properties";
public String mySketchPath;
/**
* add a constructor
*/
public MyJavaClass(String inSketchPath) {
mySketchPath = inSketchPath;
}
public String GetPropsFileContent() {
//System.out.format(":: sketchPath: '%s'%n", sketchPath()); // if `MyJavaClass extends PApplet`, then sketchPath() just prints current working directory!
System.out.format(":: mySketchPath: '%s'%n", mySketchPath);
getLocations();
String myret = null;
myret = readgetFileContent(PROPERTIES_FILENAME);
return myret;
}
public String readgetFileContent(String inFileName) {
String result = null;
Properties properties = new Properties();
try {
//String theFilePath = inFileName; // verbatim relative path fails
Path inFileNameSketchPath = Paths.get(mySketchPath, "data", inFileName); // OS path join
String theFilePath = inFileNameSketchPath.toString();
System.out.format(":: theFilePath: '%s'%n", theFilePath);
//InputStream in = MyJavaClass.class.getResourceAsStream(theFilePath); // no can do, is 'null', also w/ abs path
//InputStream in = new FileInputStream( new File(theFilePath) ); // OK, but not seekable
FileInputStream in = new FileInputStream( new File(theFilePath) );
properties.load(in);
// double-check loaded properties:
for(String key : properties.stringPropertyNames()) {
String value = properties.getProperty(key);
System.out.format(":: properties: key '%s' => value '%s'%n", key, value);
}
ByteArrayOutputStream resultbaos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
in.getChannel().position(0); // do reset - seek 0 (start), to reset stream again for reading
while ((length = in.read(buffer)) != -1) {
resultbaos.write(buffer, 0, length);
}
result = resultbaos.toString();
} catch (IOException e) {
System.err.println("There was an error reading " + inFileName + ": " + e.getCause()
+ " : " + e.getMessage());
} catch (Exception e) {
System.err.println("There was an exception " + inFileName + ": " + e
+ " : " + e.getMessage());
}
return result;
}
public void getLocations() {
URL classURL = getClass().getProtectionDomain().getCodeSource().getLocation();
System.out.format(":: The URL is '%s';%n", classURL); // file:/tmp/testprocjavapath3056820301028631180temp/
String s = getClass().getName();
int i = s.lastIndexOf(".");
if(i > -1) s = s.substring(i + 1);
s = s + ".class";
System.out.println(":: name: " + s);
Object resourcePath = this.getClass().getResource(s);
System.out.println(":: resourcePath: " + resourcePath); // file:/tmp/testprocjavapath9185318125154993853temp/MyJavaClass.class
}
}
EOF
# run once:
"$PROCBINPATH"/processing-java --sketch="$MYSKETCHDIR" --run

Want to compare [.so] files in two apk's

I want to compare the names (text) of .so files in two apk's
I write a batch script for pulling the app. Now , the app is at a desired location. How can i compare .so files.I am using java.util.zip for unzipping purpose and then trying to compare the directory structure.
My code is
import java.io.*;
import java.lang.Runtime;
public class batchrun {
public static void main(String[] args) {
try {
String[] command = {"cmd.exe", "/C", "Start", "C:\\test1.bat"};
Process p = Runtime.getRuntime().exec(command);
}catch (IOException ex){}
}
}
and my batch file is
#echo off
cd C:\app1
set /p UserInputPath= enter path
adb pull %UserInputPath%
I am clueless as in how to proceed from here

Get the list of all files under the folder resources

My unit test project structure looks like this:
.
└── src
└── test
├── java
│ └── foo
│ └── MyTest.java
└── resources
├── file1
|-- ...
└── fileN
In MyTest.java, I would like to get a list of all files under src/test/resources/ :
File[] files = GET_ALL_RESOURCE_FILES();
how to do it in Java?
Try this as your code:
File Selected_Folder = new File(System.getProperty("user.dir")+"/src/test/resources/");
File[] list_of_files = Selected_Folder.listFiles();
For viewing the files under that particular directory from where you have selected the files... you can do this...
for(int i=0; i<list_of_files.length; i++)
{
System.out.println(" File Number "+(i+1)+" = "+list_of_files[i]);
}
My Approach--
File[] GET_ALL_RESOURCE_FILES(final File file)
{
java.util.List<File> ls = new ArrayList<File>();
for (final File fileIter : file.listFiles()) {
if (fileIter.isDirectory())
loadAll(fileIter);
else
ls.add(fileIter);
}
return ls.toArray();}
Now call this function--
File[] files = GET_ALL_RESOURCE_FILES('src/test/resources/');
Try this File folder = new File(System.getProperty("user.dir")+"/src/test/resources/");
File[] files = folder.listFiles();
System.getProperty("user.dir") will return path of your current working directory. In maven projects it returns path of your maven project folder which is parent folder of src folder.

Runnable jar file does not find resources

I have created a jar file that runs the login screen. When I enter the user's credentials, it uses an XML file to validate the credentials. My jar file does not seem to find this XML file. Here is my file directory:
My jar file is created like this:
The users.xml file is loaded like this
URL url = getClass().getResource("/users.xml");
String path = url.getPath();
String loginQuery = "for $x in doc('"+ path +"')//User where ($x/Username='" + username +"') "
+ " and ($x/Password='" + password + "') return data($x/Name)";
My project works fine on eclipse when I run it. I have no idea why my jar doesn't work
I think that's a problem with your packaging. I just compiled a test program, showing stuff works as expected:
mabi#terra ~ $ cat /tmp/test/Test.java
import java.net.URL;
public class Test {
public static void main(String[] args) {
Test instance = new Test();
URL absDynRes = instance.getClass().getResource("/users.xml");
if (absDynRes == null) {
System.out.println("Absolute dynamic URL is null");
} else {
System.out.println("Got: " + absDynRes);
}
}
}
Compile and run:
mabi#terra ~ $ cd /tmp/test/ && javac Test.java
mabi#terra /tmp/test $ jar cfe test.jar Test -C /tmp/test Test.class users.xml
mabi#terra /tmp/test $ java -jar test.jar
Got: jar:file:/tmp/test/test.jar!/users.xml
Either you don't have the file in your jar or the class returned by getClass() resides in a different jar then the one containing users.xml.

*Nix ls Command in Java

Anyone aware of a method/class/library that will allow me to easily reproduce the results of the *nix ls -l command in Java? Calling ls directly is not an option due to platform independence.
eg.
$ls -l myprogram.exe
-rwxrwxrwx 1 auser None 1261568 Nov 15 17:41 C:\myprogram.exe
Here is a tutorial on getting a directory listing in java with sample source code.
Here's an implementation of ls -R ~, which lists files recursively starting in the home directory:
import java.io.*;
public class ListDir {
public static void main(String args[]) {
File root;
if (args.length > 0) root = new File(args[0]);
else root = new File(System.getProperty("user.dir"));
ls(root);
}
/** iterate recursively */
private static void ls(File f) {
File[] list = f.listFiles();
for (File file : list) {
if (file.isDirectory()) ls(file);
else System.out.println(file);
}
}
}
This provides what you are looking for:
You can use the java.nio.file package.
I think we don't have ready to use Java class in java stadard library.
But you can develop a tool like *nix ls -l tool by using classes in java.io package.

Categories