Java os path operations, joins, and moving up levels - java

I have 2 related questions regarding files, and the File class in Java.
I gather the best practice way to build a path - and have it OS agnostic - is like this:
File file = new File("dir" + File.separator + "filename.ext");
My first question is, "Is there a Java equivalent of python os.path.join function built into Java?"
i.e. Is there a function where I can do something like this:
String path = some_func("arbitrary", "number", "of", "subdirs", "filename.ext");
I suspect if such a thing exists, I may need to pass an Array of Strings to the function, rather than an arbitrary number of args, but the above would be ideal.
But regardless of the answer to the question above, my second question is, "is there a built in way to move a level up when specifying a path?"
i.e. Is the correct way, to do something like this:
String rel_path = ".." + File.separator + "filename.ext";
Or is there something like this:
String rel_path = File.level_up + File.separator + "filename.ext";
Cheers all!

I gather the best practice way to build a path - and have it OS agnostic - is like this:
File file = new File("dir" + File.separator + "filename.ext");
Or like this (see the API documentation on the constructors of java.io.File):
File file = new File("dir", "filename.ext");
Note that this takes only two parameters - the name of the parent directory and the filename (not an arbitrary list of subdirectories).
You're looking for java.nio.file.Paths.get():
Path path = Paths.get("arbitrary", "number", "of", "subdirs", "filename.ext");
Note that gives you a Path rather than a File, if you really need a File then call toFile() on the Path.
Note: This is all new stuff in Java 7.

Not that I know of for Java 6, but you could use Apache's StringUtils to achieve the same effect:
StringUtils.join(components, File.separator)
As above, where components is an Iterable or an array of your file path components.
e.g. String path = StringUtils.join(new String[] {"foo", "bar"}, File.separator);

On your first question, Jesper is right imo that java.nio.Pages.get() is best if you're using java 7.
On the second part of your question, consider using:
file.getParentFile().getName();
To navigate to the parent of the given file (or dir).

Related

How to create a File object with a String

In my TestClass I want to read the txt-file. I am always very confused how I should go about getting a reference to the txt-file though. The example I dug out of the internet suggested using a BufferedReader which requires a Path object to instantiate. I thought I'd create a File object and invoke it's .toPath(). But now how do I instantiate my File object? The least scary of its constructors require a string, but which string?
The easiest way to reference the file path within the scope of your project would be to use the System properties. Using the below value would return to you the users current working directory. Something like this would do the trick:
File file = new File (System.getProperty ("user.dir") + "/" + path_to_txt_file);
Depending on your system you may need to modify the delimiter.

Identify extension of a file based on its stem name

I have a simple problem that I am quite struggling with. I have several files in a directory and I am reading them and passing processing them based on their type (extension). However, as an input, I receive a path to the file without extension so I have to identify the type myself.
example (files):
files/file1.txt
files/file1.txt
files/pic1.jpg
----------------
String path = "files/file1";
String ext = FilenameUtils.getExtension(path); // this returns null
Is there a way to identify the type of file when the extension is not included in the path?
Your best bet here is to "do it yourself" by implementing instances of FileTypeDetectors.
When you have this, you can then just use Files.probeContentType() to have a string returned which describes the file contents as a MIME type.
The JDK does provide a default implementation but it relies on file extensions, basically; if you have a PNG image named foo.txt, the default implementation will return text/plain where the file is really an image/png.
Which is of course wrong.
Final note: if all you really have is only part of the file name, then use Files.newDirectoryStream() and provide it with the appropriate DirectoryStream.Filter<Path>. Not sure yet why you only have part of it though.
Since you're only given part of the file name, you'll need to search for files that start with that prefix. Note that there could be multiple matches.
Using java.nio.file
Path prefix = Paths.get(path);
Path directory = prefix.getParent();
try (Stream<Path> stream = Files.list(directory)) {
stream.filter(p -> p.getFileName().startsWith(prefix.getFileName() + "."))
.forEach(p -> System.out.printf("Found %s%n", p));
}
Using java.io
File prefix = new File(path);
File directory = prefix.getParentFile();
List<File> matches = directory.listFiles((dir, name) ->
name.startsWith(prefix.getName() + "."));
for (File match: matches) {
System.out.printf("Found %s%n", match);
}
Files.probeContentType(Path) implements a basic MIME type inquiry you can use (or extend), the internal details of which are platform specific. You can also make a little utility method that walks a Set of extensions. A combination of the two approaches may be necessary, depending on your application.
The MIME type checker will give different results on different releases implementations of the JRE. So, always have a fail-over solution.
See: http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#probeContentType%28java.nio.file.Path
[EDIT]
This actually does not answer the question posited, as this method needs a full, legal Path object to work on. If you are given just the stem name, and the extension is missing, then you neither have an extension to work with nor a valid Path name for Files to work with [and probeContentType() may, in some implementations, just use the extension anyway.]
I'm not sure how you can do this without Path that refers to a real on-disk file that the JRE can access, or by hand if you don't have an extension. If you don't have a File of some sort, you can't even open it up yourself to attempt file type "magic".

Convert Windows style path into unix path in java code

I am working in a java code that was designed to run on windows and contains a lot of references to files using windows style paths "System.getProperty("user.dir")\trash\blah". I am in charge to adapt it and deploy in linux. Is there an efficient way to convert all those paths(\) to unix style (/) like in "System.getProperty("user.dir")/trash/blah". Maybe, some configuration in java or linux to use \ as /.
My approach is to use the Path object to hold the path information, handle concatenate and relative path. Then, call Path's toString() to get the path String.
For converting the path separator, I preferred to use the apache common io library's FilenameUtils. It provides the three usefule functions:
String separatorsToSystem(String path);
String separatorsToUnix(String path);
String separatorsToWindows(String path)
Please look the code snippet, for relative path, toString, and separator changes:
private String getRelativePathString(String volume, Path path) {
Path volumePath = Paths.get(configuration.getPathForVolume(volume));
Path relativePath = volumePath.relativize(path);
return FilenameUtils.separatorsToUnix(relativePath.toString());
}
I reread your question and realize you likely don't need help writing paths. For what you're trying to do I am not able to find a solution. When I did this in a project recently I had to take time to convert all paths. Further, I made the assumption that working out of the "user.home" as a root directory was relatively sure to include write access for that user running my application. In any case, here are some path problems I addressed.
I rewrote the original Windows code like so:
String windowsPath = "C:\temp\directory"; //no permission or non-existing in osx or linux
String otherWindowsPath = System.getProperty("user.home") + "\Documents\AppFolder";
String multiPlatformPath = System.getProperty("user.home") + File.separator + "Documents" + File.separator + "AppFolder";
If you're going to be doing this in a lot of different places, perhaps write a utility class and override the toString() method to give you your unix path over and over again.
String otherWindowsPath = System.getProperty("user.home") + "\Documents\AppFolder";
otherWindowsPath.replace("\\", File.separator);
Write a script, replace all "\\" with a single forward slash, which Java will convert to the respected OS path.

Concatenating Strings in Java generates between-in null

This question looks like very similar to: Concatenating null strings in Java
But my issue is some different.
I want to build an absolute path to a file:
String path = properties.get("path"); // returns /home/myuser/relativepath/ , ends with bar /
String file = currentFile; // currentFile values "file.txt"
String result = path + file; // this results in /home/myuser/relativepath/nullfile.txt
Why is there than 'null' text? That's the reason my application does not work now.
I have review it in Windows and Linux.
In Windows it works perfectly.
In Linux, I have this issue.
I uploaded properties file and then, edited with vi command.
Maybe is this the problem?
Shouldn't I use this way to generate an absolute path, and use File.Separator property in Java?
EDIT: I have post my final right answer with detailed steps. I hope it would be useful.
My bet (though I have not seen Java behave this way) is there's a null-ish character (such as a carriage return) of some sort in your properties file which Windows handles at the OS level so Java/Properties doesn't see it.
As a first pass, try printing the length and last few characters of your path string, e.g.:
for(int i = Math.max(0, path.length()-5); i < path.length(); i++) {
System.out.print(path.charAt(i)+":"+((int)path.charAt(i))+" ");
}
System.out.println(path.length());
Willing to bet the last character, on Linux, is not what you'd expect. The right fix would then be to clean up your properties file so that it's compatible on both OSes.
Well, the complete and detailed steps to fix my issue are these (maybe any of them could not be necessary, but I prefer to write them all):
Create config file in Linux with vi, emacs, ... (not upload file from Windows).
Edit file with vi, emacs... At the end of each path, do not include directory separator character ( / ).
Check variables before contatenate them. Make sure they don't have any space and other unexpected character.
Concatenate variables with:
String result = path + File.separator + file;
I hope this would be useful. Thank you all for your suggestions.
Regards
What do you expect?
Yo´re doing a String result = path + result;
int a = 1 + a would be similar... don´t use a variable to init itself.
(That can´t be your code in the first place, if you´re getting this output.)
result is path+file :
String path = properties.get("path");
String file = currentFile;
String result = path + file;
^
change here
the result is: /home/myuser/relativepath/file.txt

reconstructing a file path in java

I have a file path location as such:
Properties readProp = \\192.168.41.84\dev\config\dev\config.properties
how can I manipulate it so I remove the portion of config.properties
and replace it with test\config.properties
so the new Properties location would be:
Properties readProp = \\192.168.41.84\dev\config\dev\test\newconfig.properties
?
thanks for your time and effort
Make sure you escape any backslashes you have as you build the string.
String path = "\\\\192.168.41.84\\dev\\config\\dev\\config.properties";
System.out.println(path);
int lastBackSlash = path.lastIndexOf("\\");
//+1 to include lastBackSlash
String newPath = path.substring(0, lastBackSlash + 1) + "test" + path.substring(lastBackSlash);
System.out.println(newPath);
Prints
\\192.168.41.84\dev\config\dev\config.properties
\\192.168.41.84\dev\config\dev\test\config.properties
This article like this is also decent read. Treating paths as strings can be dangerous.
http://twistedoakstudios.com/blog/Post4872_dont-treat-paths-like-strings
However, if your careful, know what how your string functions behave(or look them up), and you don't have off by 1 errors... then treating the paths like strings should be pain free. But you will have no guarantee that the path is valid... while a path builder library would give you that assurance.

Categories

Resources