Creating Symbolic Links with Java at Runtime
January 4th, 2009
For the time being it seems that there is no other way than calling an external program for doing the job:
The disadvantage of this method is the overhead for creating the new process. This can be a serious downgrade in performance if you have to execute this code frequently.
Here is an alternative solution that can vastly improve speed.
First you write a small program in C, say it symlinkcreator.c. This is the actual worker:
You can compile the program by running this command:
This will give you the symlinkcreator executable file.
Then you going to need an elegant wrapper class that will call the C program:
Have done these, you can then easily create symbolic links from you code, like this:
Downloads:
symlinkcreator.c
SymlinkCreator.java
Alternatively, you can use native methods to eliminate the hassle of inter-process communication between two separate processes.
First create a Symlink class that defines the signatures of the native mathod. This class will act as an interface to the actual C functions:
Then you will need to generate a header file for this class using the javah utility:
This will generate a header file that looks like this:
Then you will have to write a small C file that will define the implemtation of the function:
Then you have to compile the C file as a shared library:
You will have to load this shared library at the runtime of your java program.
Finally you can write a small test program to see that everything works:
Process process = Runtime.getRuntime().exec( new String[] { "ln", "-s", oldName, newname } );
process.waitFor();
process.destroy();The disadvantage of this method is the overhead for creating the new process. This can be a serious downgrade in performance if you have to execute this code frequently.
Here is an alternative solution that can vastly improve speed.
First you write a small program in C, say it symlinkcreator.c. This is the actual worker:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
int main()
{
char st[1024];
char oldpath[1024];
int count = 0;
while (fgets(st,sizeof(st),stdin) != NULL)
{
for (char *cp = st; *cp; cp++)
if (*cp == '\n' || *cp == '\r') *cp = '\0';
if (count++ % 2)
symlink(oldpath,st);
else
strcpy(oldpath,st);
}
}You can compile the program by running this command:
# gcc symlinkcreator.c -o symlinkcreator -std=c99This will give you the symlinkcreator executable file.
Then you going to need an elegant wrapper class that will call the C program:
import java.io.IOException;
import java.io.PrintWriter;
public class SymlinkCreator
{
private Process process;
private PrintWriter out;
public SymlinkCreator( String path ) throws IOException
{
process = Runtime.getRuntime().exec(path);
out = new PrintWriter(process.getOutputStream());
}
public void link( String oldpath, String newpath )
{
out.println(oldpath);
out.println(newpath);
out.flush();
}
public void terminate() throws InterruptedException
{
out.close();
process.waitFor();
process.destroy();
}
}Have done these, you can then easily create symbolic links from you code, like this:
// You only need one single SymlinkCreator object (just a single unix process is created)
SymlinkCreator symlinkCreator = new SymlinkCreator("/path/to/symlinkcreator");
...
// Create as many symbolic links as you want using the same process
symlinkCreator.link(oldName,newName);
...
// Terminate the symbolic creator process and release resources when done.
symlinkCreator.terminate();Downloads:
symlinkcreator.c
SymlinkCreator.java
Alternatively, you can use native methods to eliminate the hassle of inter-process communication between two separate processes.
First create a Symlink class that defines the signatures of the native mathod. This class will act as an interface to the actual C functions:
public class Symlink
{
public native static void create( String oldpath, String newpath );
}Then you will need to generate a header file for this class using the javah utility:
# javah -classpath /path/to/your/classes SymlinkThis will generate a header file that looks like this:
Symlink.h
#include <jni.h>
/* Header for class Symlink */
#ifndef _Included_Symlink
#define _Included_Symlink
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Symlink
* Method: create
* Signature: (Ljava/lang/String;Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_Symlink_create
(JNIEnv *, jclass, jstring, jstring);
#ifdef __cplusplus
}
#endif
#endifThen you will have to write a small C file that will define the implemtation of the function:
Symlink.c
#include <unistd.h>
#include <jni.h>
#include "Symlink.h"
JNIEXPORT void JNICALL Java_Symlink_create
(JNIEnv *env, jclass obj, jstring oldpath, jstring newpath)
{
const char *nativeOldpath = (*env)→GetStringUTFChars(env, oldpath, 0);
const char *nativeNewpath = (*env)→GetStringUTFChars(env, newpath, 0);
symlink(nativeOldpath,nativeNewpath);
(*env)→ReleaseStringUTFChars(env, oldpath, nativeOldpath);
(*env)→ReleaseStringUTFChars(env, newpath, nativeNewpath);
}Then you have to compile the C file as a shared library:
# gcc -shared -o Symlink.so Symlink.c -I /path/to/jdk/include -I /path/to/jdk/include/linuxYou will have to load this shared library at the runtime of your java program.
Finally you can write a small test program to see that everything works:
public class TestSymlink
{
public static void main( String[] args )
{
System.load("/path/to/Symlink.so");
Symlink.create("/home/giannis/test1", "/home/giannis/test2");
}
}