I was making a Java game that stores options and the LWJGL jars in the standard application data storage directory (I think that's C:\Users\user\AppData\roaming\application on Windows, ~/.application on Linux, and ~/Library/Preferences on Mac). Currently I just use System.getProperty(os.name) and have an if-else to select the right file path (which uses system.getProperty(user.home) and appends the correct file path to it). However, this might not work on some weird OSs because the if-else won't find Windows, Mac, or Linux in the OS name, and this also seems to be a very bad way to do this in general (also the if-else assumes the OS is Linux if it isn't Windows or Mac). I tried decompiling Minecraft, which stores the app data and the LWJGL jars in the correct path, but the code is obfuscated. Is there any better way for me to do this, or should I stick with an if-else on os.name?
Java Preferences API was created specifically for such purpose.
For configuration preferences, there is the Java Preferences API.
For other files, I have not found a solution to this. The best solution, at present, is probably to dispatch on the OS type with a fallback based on the user.home property.
On Linux/Unix (not Mac), you might want to honor the XDG Base Directory specification.
Shouldn't a path like this work everywhere, i.e. without the if-else-if:
String userHome = System.getProperty("user.home");
if (!userHome.endsWith("/")) {
userHome += "/";
}
String targetPath = userHome + ".myapp/settings.properties";
Related
I developed a software in netbeans + Ubuntu and then converted the runnable .jar file of netbeans to .exe file using a converter software.
I used:
File f = new File("./dir/fileName");
which works fine in Ubuntu but it gives an error in Windows, because the directory pattern of both OSs are different.
Absolute paths should not be hardcoded. They should be read e.g. from a config file or user input.
Then you can use the NIO.2 File API to create your file paths: Paths.get(...) (java.io.File is a legacy API).
In your case it could be:
Path filePath = Paths.get("dir", "fileName");
I used: File f = new File("./dir/fileName") which works fine in Ubuntu but it gives error in Windows, bcz the directory pattern of both os are different.
It is presumably failing because that file doesn't exist at that path. Note that it is a relative path, so the problem could have been that the the path could not be resolved from the current directory ... because the current directory was not what the application was expecting.
In fact, it is perfectly fine to use forward slashes in pathnames in Java on Window. That's because at the OS level, Windows accepts both / and \ as path separators. (It doesn't work in the other direction though. UNIX, Linux and MacOS do not accept backslash as a pathname separator.)
However Puce's advice is mostly sound:
It is inadvisable to hard-code paths into your application. Put them into a config file.
Use the NIO2 Path and Paths APIs in preference to File. If you need to assemble paths from their component parts, these APIs offer clean ways to do it while hiding the details of path separators. The APIs are also more consistent than File, and give better diagnostics.
But: if you do need to get the pathname separator, File.separator is an acceptable way to get it. Calling FileSystem.getSeparator() may be better, but you will only see a difference if your application is using different FileSystem objects for different file systems with different separators.
You can use File.separator as you can see in api docs:
https://docs.oracle.com/javase/8/docs/api/java/io/File.html
Is there a platform-independent Java statement to load a native library from a different directory than the Java source code is in? I would like to use something like this:
public class HelloWorld {
static {
System.loadLibrary("../some_project/HelloWorld");
}
public static native void print();
}
The problem is that System.loadLibrary() doesn't support directory separators in the pathname argument. Also, System.load() unfortunately requires an absolute pathname, which not only means I can't specify a relative directory as above (which I would like to do), but it also requires the argument to include, for example, the preceding "lib" and ".so" extension on the JNI library name on a Linux system.
Is there a standard way of dealing with this? If possible, I would like to avoid writing a bunch of platform-dependent Java code just to construct the correct JNI library name.
I believe you're looking for System.mapLibraryName, which is the method typically used by ClassLoader.findLibrary implementations. For example:
File lib = new File("../some_project/" + System.mapLibraryName("HelloWorld"));
System.load(lib.getAbsolutePath());
This will use libHelloWorld.so on Linux and HelloWorld.dll on Windows. Be aware that some operating systems support multiple extensions, and mapLibraryName can only support one, by design. The ones I'm aware of are MacOS (.dylib primarily and .jnilib for legacy) and AIX (.a and .so).
Well, as you have clearly explained, you can't use loadLibrary. And so that leaves load. But that requires an absolute path. So, expand your relative path into an absolute path using your preferred file path utility functions, and pass that on to load. This may seem inconvenient but it's much more robust than relying on the vagaries of library search paths.
I am trying to use IM4J (a Java wrapper for ImageMagick) to create thumbnails of JPEGs and it is my first experience (ever) with both libraries. Please note that this is a hard requirement handed to me by my tech lead (so please don't suggest to use anything other than an IM4J/ImageMagick) solution - my hands are tied on the technology choice here!
I am getting a FileNotFoundException on the and convert command which tells me I don't have one of these libraries (or both) setup correctly.
On my computer, here is my directory structure:
C:/
myApp/
images/ --> where all of my JPEGs are
thumbnails/ --> where I want ImageMagick to send the converted thumbnails to
imageMagickHome/ --> Where I downloaded the DLL to
ImageMagick-6.7.6-1-Q16-windows-dll.exe
...
In my Java project, I make sure that the IM4J JAR (im4java-1.2.0.jar) is on the classpath at runtime. Although I am required to use the 1.2.0 version of IM4J, I have the liberty to use any version of ImageMagick that I want. I simply chose this version because it seemed like the most current/stable version for my Windows 7 (32-bit) machine. If I should use a different version, please send me a link to it from the ImageMagick downloads page in your answer!
As for ImageMagick, I just downloaded that EXE from here and placed it in the folder mentioned above - I didn't do any installation, wizard, MSI, environment variable configuration, etc.
Then, in my Java code:
// In my driver...
File currentFile = new File("C:/myApp/images/test.jpg"); --> exists and is sitting at this location
File thumbFile = new File("C:/myApp/thumbnails/test-thumb.jpg"); --> doesnt exist yet! (destination file)
Thumbnailer myThumbnailer = new Thumbnailer();
myThumbnailer.generateThumbnail(currentFile, thumbFile);
// Then the Thumbnailer:
public class Thumbnailer
{
// ... omitted for brevity
public void generateThumbnail(File originalFile, File thumbnailFile)
{
// Reads appConfig.xml from classpath, validates it against a schema,
// and reads the contents of an element called <imPath> into this
// method's return value. See below
String imPath = getIMPathFromAppConfigFile();
org.im4java.core.IMOperation op = new Operation();
op.colorspace(this.colorSpace);
op.addImage(originalFile.getAbsolutePath());
op.flatten();
op.addImage(thumbnailFile.getAbsolutePath());
ConvertCmd cmd = new ConvertCmd();
cmd.setSearchPath(imPath);
// This next line is what throws the FileNotFoundException
cmd.run(op);
}
}
The section of my appConfig.xml file that contains the imPath:
<imPath>C:/myApp/imageMagickHome</imPath>
Please note - if this appConfig.xml is not well-formed, our schema validator will catch it. Since we are not getting schema validation errors, we can rule this out as a culprit. However, notice my file path delimiters; they are all forward slashes. I did this because I was told that, on Windows systems, the forward slash is treated the same as a *nix backslash, in reference to file paths. Believe it or not, we are developing on Windows
machines, but deploying to linux servers, so this was my solution (again, not my call!).
IM4J even acknowledges that Windows users can have trouble sometimes and explains in this article that Windows developers might have to set an IM4JAVA_TOOLPATH env var to get this library to work. I tried this suggestion, created a new System-wide environmental variable of the same name and set its value to C:\myApp\imageMagickHome. Still no difference. But notice here I am using backslashes. This is because this env var is local to my machine, whereas the appConfig.xml is a config descriptor that gets deployed to the linux servers.
From what I can tell, the culprit is probably one (or more) of the following:
I didn't "install" the ImageMagick EXE correctly and should have used an installer/MSI; or I need to add some other environmental variables for ImageMagick (not IM4J) itself
Perhaps I still don't have IM4J configured correctly and need to add more environmental variables
Could be the Windows/*nix "/" vs. "" issue from my appConfig.xml file as mentioned above
I'm also perplexed as to why I'm getting a FileNotFoundException on a file named "convert":
java.io.FileNotFoundException: convert
I assume this is a batch/shell file living somewhere inside the IM4J jar (since the only thing I downloaded for ImageMagick was the EXE). However, if I extract the IM4J jar I only see classes inside of it. I see "script generator" classes, so I assume these kick off before my cmd.run(op) call and create the convert file, and maybe that's what I'm missing (perhaps I need to manually kick off one of these generators, like CmdScriptGenerator prior to executing my Thumbnailer methods. . Or, maybe my download is incomplete.
Either way, I'm just not versed enough with either library to know where to start.
Thanks for any help with this.
Run the 'ImageMagick-6.7.6-1-Q16-windows-dll.exe' installer first to install the imagemagick libraries. Then make sure your environment path includes the location of the installed binaries ('convert.exe', 'mogrify.exe', etc)
Make sure u have Set the environment-variable IM4JAVA_TOOLPATH.
I have for example .pdf file (path to that file). How to open this file in default application (probably Acrobat Reader) from SWT application (for example on Button click) ?
You should be able to use:
Program.launch(file);
to open the file (using the default application or creator). From the javadoc:
Launches the operating system executable associated with the file or URL (http:// or https://). If the file is an executable then the executable is launched. Note that a Display must already exist to guarantee that this method returns an appropriate result.
Note that there are some peculiarities in Program.launch() (or at least there were, though these may have been fixed in more recent versions of the runtime.) I don't really remember the specifics of the bugs, but we do some checks to work around some issues:
If you're on a Unix platform, and you're specifying an absolute path, there may be trouble opening that file. We prefix absolute paths with /. - so that /tmp/foo would be translated to /./tmp/foo - although I don't really remember the specifics of this bug any more than that.
On Windows, if you're trying to open a UNC path - for example \\server\bar - you need to wrap the string in double-quotes. For example: Program.open("\"\\server\bar\"");
Try Desktop.open:
Desktop.getDesktop().open(file);
Maybe this can help to find a decision: we ran into PermGen space trouble upon call Desktop.open() - which is in AWTpackage - out of our SWT application.
So I would prefer Program.launch() over Desktop.open() in a SWT-environment.
As the title says, the java.io.tmpdir property in Java is really nice, and I can't find an equivalent for C. I'm writing for Windows and in Visual Studio. I don't want to just use something like C:\Temp because in later versions of windows the appropriate directory could be something like C:\Users\[UserName]\AppData\Local\Temp and a way to retrieve this would be much easier. I want a directory and not just a temp file because I'm downloading and executing a file from the internet.
As a side note, if anyone can give me tips about how to better google for C stuff it would be much appreciated :)
If you're using the Win32 API, you can use GetTempPath().
It is not quite what you were asking, but in the C standard library:
tmpnam_r will create a filename
string
tmpfile will create and open a
file (returning a FILE*)
See: http://www.gnu.org/s/libc/manual/html_node/Temporary-Files.html for more possibilities
For the directory itself, you can either get the dirname of the filename generated by the above functions, or in Windows you can get the environmental variable TEMP, and on Unix-likes you can either get the variable TMPDIR or use /tmp if TMPDIR is not set