Recursive directory creation fails on device - java

My code runs in the simulator, but crashes on Android with a FileNotFoundException as it tries to FileSystemStorage#openOutputStream in an non-existing directory. I create all the needed directories recursively before using
private void ensureParentDirs(String file) {
final int j = file.lastIndexOf("/");
final String s = file.substring(0, j);
if (storage.isDirectory(s)) return;
storage.mkdir(s);
if (storage.isDirectory(s)) return;
ensureParentDirs(s);
storage.mkdir(s);
if (storage.isDirectory(s)) return;
Log.p("Cannot create directory: " + s);
}
which is supposed to work like new File(file).getParentFile().mkdirs(). It might be wrong, but then it shouldn't run in the simulator either, so I'd call it a bug.
I get the message
Cannot create directory:
file:///data/user/0/my.package.name/files//dump/000/abcd
but the parent directory ("000") has been successfully created. Using adb shell, I can create the directory using
mkdir /data/data/my.package.name/files/dump/000/abcd
so I can't see what's wrong. Any idea?

There was (possibly still existent) problem with double slashes. My path was
/dump/000/abcd
and I transformed it via
path -> APP_HOME_PATH + "/" + path
into
file:///data/user/0/my.package.name/files//dump/000/abcd
which failed because of the double slashes, while
dump/000/abcd
transforms into
file:///data/user/0/my.package.name/files/dump/000/abcd
and works correctly.

Related

Run shell inside watch service in java

I want to run shell script inside watch service class to run the shell after new file add to folder.
Watch service is working perfectly but when I want to add Runtime.getRuntime().exec("home/user/test.sh"); I recived error.
I just add Runtime after this:
// Dequeueing events
Kind<?> kind = null;
for(WatchEvent<?> watchEvent : key.pollEvents()) {
// Get the type of the event
kind = watchEvent.kind();
if (OVERFLOW == kind) {
continue; //loop
} else if (ENTRY_CREATE == kind) {
// A new Path was created
Path newPath = ((WatchEvent<Path>) watchEvent).context();
// Output
System.out.println("New path created: " + newPath);
Runtime.getRuntime().exec("home/user/test.sh")
What I have to do?
I thing problems with running script have nothing to do with WatchService, since you don't post actual exception that is throws (that would help a lot) I can only guess what is wrong, so please check this:
Script doesn't have permission to execute (easily fixable by chmod +x path/to/script.sh) - in that case you would get IOException with message like Permission denied or similar
System cannot find your script, since you are using relative path (no / at the beginning of script name) in that case ether use full script name e.g. /home/user/foo/script.sh or use proper relative path ../foo/script.sh - you should check if script exists before running it via exec (How do I check if a file exists in Java?)
Beware that script may be called with working directory of running Java program - so you should pass newly created file path as parameter to script to make it independent of its location
I followed tutorial that you were using with code:
if (OVERFLOW == kind) {
continue; //loop
} else if (ENTRY_CREATE == kind) {
// A new Path was created
Path newPath = ((WatchEvent<Path>) watchEvent).context();
// Output
System.out.println("New path created: " + newPath);
Runtime.getRuntime().exec(new String[] { "/home/xxx/foo.sh", newPath.toString() });
}
and script:
#!/bin/bash
echo "FILE CREATED: $1" >> /home/xxx/watch_dir.log
and it worked without any errors.

Cloning java application on Windows

I am trying to start a new process with Runtime.exec() from my javafx application.
The new process is my javafx application (but in a new process, the "parent" one will still be open).
So I run javaw via the exec method and tell it my classpath. And here is my problem: the classpath contains whitespaces, so I need to quote every path. But I retrieve the path at runtime via java.class.path (since it is the same application).
Do I need to process the string and quote everything or is there an easy way to get this to work?
Here is the code:
public static void startInNewProcess() {
try {
Runtime r = Runtime.getRuntime();
File javaPath = new File(System.getProperty("java.home"), "bin/javaw");
File classPath = new File(System.getProperty("java.class.path"));
System.out.println("java loc: " + javaPath.toString());
System.out.println("classpath: " + classPath);
Process p = r.exec(javaPath.toString() + " -classpath " + classPath.getPath());
} catch (Exception e) {
e.printStackTrace();
}
}
I get the following string as classpath:
classpath: C:\Users\kwilhelm\git\ResourcePlaner\bin;C:\Program Files (x86)\eclipse\plugins\org.eclipse.fx.ide.css.jfx8_2.0.0.201506111511.jar;C:\Users\kwilhelm\git\ResourcePlaner\lib\itextpdf-5.5.6-javadoc.jar;C:\Users\kwilhelm\git\ResourcePlaner\lib\itextpdf-5.5.6-sources.jar;C:\Users\kwilhelm\git\ResourcePlaner\lib\itextpdf-5.5.6.jar;C:\Users\kwilhelm\git\ResourcePlaner\lib\controlsfx-8.40.9.jar
But javaw gives the error that it can't find mainclass "Files", so it can't handle the whitespace in the path.
So is there a way to get the classpath with quotes?
Is there a better solution?
Any help is apreciated
And here is my problem: the classpath contains whitespaces, so I need to quote every path.
Actually, no you don't.
And in fact, if you do attempt to quote every path, it is likely to mess up bigtime, because exec doesn't understand shell quoting.
What you actually need to do is this:
Process p = r.exec(new String[] {javaPath.toString(),
"-classpath",
classPath.getPath()});
This tells exec exactly where the boundaries of the command arguments are, so that it doesn't need to try (and fail) to figure it out for itself.
In fact, that still isn't right. You also need to add:
any other JVM options that the cloned instance needs,
a class name, and
any arguments required after the classname.
The classname is mandatory. (You left it out, and that is why the java command was outputting its help message!)

Strange error when deleting directory from Java: 0 bytes, access denied

I have written method that recursively deletes directory with its contents.
Code is executed on Windows - Eclipse - JVM7
Here's the code:
/**
* Empty and delete a folder with recursion.
*
* #param folder
* folder to empty
*/
public static boolean rmdir(final String folderPath, boolean deleteParent) {
File folder = new File(folderPath);
// check if folder file is a real folder
if (folder.isDirectory()) {
File[] list = folder.listFiles();
if (list != null) {
for (int i = 0; i < list.length; i++) {
File tmpF = list[i];
if (tmpF.isDirectory())
rmdir(tmpF.toString(), true);
tmpF.delete();
}
}
if (deleteParent && !folder.delete()) {
return false;
} else
return true;
}
return false;
}
When the code is executed no error is thrown, saying that directory has been deleted successfully.
When I open drive to confirm deletion, I can still see the folder which is now 0 bytes in size with "Access denied" error when trying to open it.
EDIT:
I am administrator, have all permissions and can R/W to this folder from Windows explorer (before Java breaks it).
My question is has anyone seen this before and what could be the cause of this??
One more thing:
It seems that the directory gets set to "DeleteOnExit" instead of "Delete" right away.
Because when program ends in Lotus Notes or Eclipse directory disappears.
Ok I got this resolved...
I was not Java issue, it was Lotus Notes/Domino issue.
Here comes the long sentence:
It seems when Lotus Notes/Domino thread creates folder "A" and some files in it using LotusScript mkdir, rmdir, and other IO methods and then executes Java VM which tries to delete folder "A" with all files in it, parent thread (Lotus Notes/Domino) gets corrupted and loses directory structure handle which results in error above.
Solution to the problem is simple Dir$() statement after Java finishes folder deletion.
When Dir$() is executed, phantom folder disappears.
Probably because the Dir$() call refreshes and releases whatever should be refreshed and released internally.
Java is probably not the best language to solve this problem in. You can do this with batch file programming in one line: rmdir <directory-to-completely-remove> /s /q. If you absolutely must do this in Java, then you can run this command from a Java program on windows with: Runtime.getRuntime().exec("cmd /C start /min cmd.exe /K \"rmdir <directory-to-remove> /s /q & exit\"");

Get the drive program is running on in Mac

I would like to find out the root of the drive that my Java application is running on in Mac. I have it working on Windows with the following code but I don't know how to make it work on OSx too:
// Method to determine and return the drive the application is running on
public static String getDriveRunningOn(){
// Get the root of all the drives attached to the computer
File[] roots = File.listRoots();
// Get the actual location of the application
// Loop through the roots and check if any match the start of the application's running path
for(int i = 0; i < roots.length; i++)
if(getAppPath().startsWith(roots[i].toString())){
String root = roots[i].toString();
//if(root.endsWith(File.separator) && root.length() > 1) root = root.substring(0, root.length() - 1);
return root;
}
// If the above loop doesn't find a match, just treat the folder the application is running in as the drive
return ".";
}
public static String getAppPath(){
try{
String appPath = MyCellRenderer.class.getProtectionDomain().getCodeSource().getLocation().getPath();
appPath = URLDecoder.decode(appPath, "UTF-8");
return new File(appPath).getAbsolutePath();
}catch(Exception e){return "n/a";}
}
So if the app was located in C:\App.exe, getDriveRunningOn() would output C:\ and so on. I need the same to happen on Mac OSX. Thanks in advance
Ok so, it turns out on Mac File.listRoots() only lists /. I'm not sure whether this is because it only sees internal drives as 'roots' or what but that's what it does. Fortunately, in Mac, all drives/volumes attacthed (including USB drives, basically those listed in Computer) appear as folders in the /Volumes directory.
Therefore, I simply added an if statement in my getDriveRunningOn() method that, if on Mac, returns new File("/Volumes").listFiles() to the file array rather than File.listRoots(). Simples :)

java code to search a file entire system, works fine on windows but infinite in linux ubuntu

Developing search utility to search a file entire computer system, works fine on windows platform but becomes an infinite process in ubuntu linux. Please help to overcome this flaw. The following is the main part of the code.
public static void fun(File f){ // root directory is passed as argument
try{
if(f.isDirectory()){
File [] fi=f.listFiles();
for(int i=0;i<fi.length;i++){
if(fileFound==true) break; // fileFound is boolean data type used as flag to indicate whether the file is found or not
System.out.println(fi[i].getName());
fun(fi[i]);
}
}
else{
if(f.getName().equalsIgnoreCase(txtFile.getText()) ||
(f.getName().toLowerCase().startsWith(txtFile.getText().toLowerCase())) ||
(f.getName().toLowerCase().endsWith(txtFile.getText().toLowerCase()))){
l.setText("file found " + f.getAbsolutePath()); // l is JLabel that indicated prints the info like file found and its path
fileFound=true;
}
}
}
catch(Exception e){
}
}
The error you are observing may be due to nested symbolic links.
The most effective approach to solve this problem would be to instead use FileUtils#iterateFiles from the excellent Apache Commons IO library.
There is something like "." (current directory) and ".." (above directory) in each dir in linux. Maybe thats your problem.
In unix like systems the first folder is "." (current folder)
and the second folder is ".." (the root folder)
you should skip the first 2 folders to avoid getting to the same folder over and over again.
try:
if(fi[i].getName() == "." || fi[i].getName() == "..")
continue;

Categories