How to make File Reading Platform Independent in Java - java

Hi I am using Maven for Selenium automation tests using Java. I am using Excel Sheet to read data for filling up a registration form. Now It is a normal Maven archetype.
src
--main
--java
--mypackage for coding goes here.
--resources
--data
-- the excel sheet
--test
-- some stuff here under java
currently if I want to read a file I am writing src/main/resources/data/theexcelsheet.xlsx
but when I share this jar, I think this will break and I don't want this to break if I package this jar.
How do I make it platform or format independent.
I am using APACHE POI Api if you are thinking how I am reading files.
Someone reading gave me idea that I might be able to use MANIFEST files to do this but I am not sure, can someone help?

If you use getResource() to point to your file, the syntax of the path always uses / to separate the components, never \ so you do not have to worry.
In general, outside of a jar, for example if you want to save application settings in a folder, you have to use a OS specific separator - you can obtain it this way:
System.out.println("my" + File.separator + "dir");
Returns my\dir on Win and my/dir on Linux
Of course, that's not enough as you cannot use hardcoded paths like the "c:" drive, but you can get the most common paths reading the System class properties, eg:
System.out.println(System.getProperty("user.home"));
returns C:\Users\piero in Windows7 and /home/piero in Linux

Related

Java Cross Platform File Operations

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

How do I move a file into a compiled .jar file using Java?

I'm making a file import system, and I can't move files into the compiled .jar file the application is in.
Here's what I'm trying to do:
Path FROM = Paths.get(filePath.getText());
Path TO = Paths.get("C:\\Users\\" + System.getProperty("user.name") +
"\\AppData\\Roaming\\.minecraft\\mods\\music_crafter-1.0\\src\\main\\resources\\assets\\music_crafter\\sounds\\block\\music_player");
//jar file
Files.move(FROM, TO.resolve(FROM.getFileName()), StandardCopyOption.REPLACE_EXISTING);
You need to handle the jar file internally. A Jar is not a directory, it is a compressed container file (pretty much a ZIP file with a different extension).
To do this, given that you are on Java 6, you have 2 options:
Unzip the contents to a temporary working directory (there are built
in APIs for this, or use a library such as Apache Commons Compress)
do your work (copying, deleting, etc) and then re-zip.
Make external command line calls to the Jar utilities that come with
Java
Of those, only (1) makes any real sense.
A third option would be available if you could up your Java to 7+ which would be:
3. Use a Zip File System Provider to to treat it as a file system in code
All that said, however:
As per comments on your question, you really might want to look at if this something you need to do at all? Why do you need to insert into existing jars? If this is 'external' data, it would be much better in a separate resource location/container, not the application jar.

Unable to extract ZIP file created with Python using zipfile.ZIP_DEFLATED compression method

I have two programs (one in Java and one in Python) that ZIP a folder, upload it to a WebServer and trigger a UNZIP method on them.
The Java version of the program works without issues and the file is extracted on the server without problems.
Here I'm using the ArchiveStreamFactory class i.e. new ArchiveStreamFactory().createArchiveOutputStream(ArchiveStreamFactory.ZIP, this.currentOutputStream);
The Python version only works if I use zipfile.ZIP_STORED method (which does not compress the file). If I use the zipfile.ZIP_DEFLATED method I get internal server error.
I don't have access to the server so for this I can only rely on what I'm able to figure out on my side.
The Java program does seem to use the ZIP_DEFLATED method also as the archive is compressed (smaller) and not just stored.
I've also run zipinfo on the both archives (the one created with Java and the one with Python with DEFLATE - which doesn't work) too see what's different.
Here's the output:
# Java
-rw---- 2.0 fat 14398 bl defN 4-Jun-15 13:55 somefile.txt
# Python
-rw-r--r-- 2.0 unx 183 b- defN 28-Jun-15 21:39 someotherfile.txt
Both seem to be compressed with DEFLATE (defN) method so why does the archive generated by Java works while the one generated by Python doesn't?
So after a lot of debugging and trial and error looks like I found the issue in case anyone else is interested or will have the same problem.
I was also adding the folder to the zip and looks like it didn't liked the folders being compressed with ZIP_DEFLATED. What I did was to manually set the compression to ZIP_STORED for folders and to ZIP_DEFLATED for files and after this it worked. Interesting how Java knew to do this automatically behind the scenes, or at least I guess it does as the Java version is kind of the same (iterate over folders/files and add them to the ZIP) except I just use the default values (so I never explicitly set the compression type for anything).
So basically my code (the version that didn't worked) was something like this:
for dir_path, dir_names, file_names in os.walk(absolute_folder_path, compression=zipfile.ZIP_DEFLATED):
...
# Add folder to ZIP
f_zip.write(absolute_dir_path, arcname=relative_dir_path)
for file_name in file_names:
...
# Add file to ZIP
f_zip.write(absolute_file_path, arcname=relative_file_path)
and the fix was this one:
for dir_path, dir_names, file_names in os.walk(absolute_folder_path):
...
# Add folder to ZIP
f_zip.write(absolute_dir_path, arcname=relative_dir_path, compress_type=zipfile.ZIP_STORED)
for file_name in file_names:
...
# Add file to ZIP
f_zip.write(absolute_file_path, arcname=relative_file_path, compress_type=zipfile.ZIP_DEFLATED)

distributing my java app, HOW do I manage directories

My java applications is almost complete and now I am giving it a finishing touch. Although certain code requires to read data from specific directories on the computer. On my machine I did it in the following way:
FileOutputStream fos=new FileOutputStream(C:/User/AnirudhVarma/Document/Appname/foldername/file,true);
But on the users machine how do I ensure that it creates it in the following directory?
C:/enduser/appname/folder/file
Hard coding folder structure in code is very bad idea.
One way to handle this is:
You need to have a properties file something like that where user need to enter path to required folder. Mention this as requirement in install docs.
In your code you need to make sure folder has required content before proceeding. If not valid folder, just show error message with proper information to setup the directory path.
System.getProperty("user.dir") will return C:/User/AnirudhVarma on you machine. From there, I'd suggest you need to consider the platform. Under windows, you should store this kind of information into the AppData folder.
So you would end up with something like System.getProperty("user.dir") + File.seperator + "AppData/Appname/foldername/file"
Under MacOS, I believe the convention is to use .AppName instead, something like System.getProperty("user.dir") + File.seperator + ".Appname/foldername/file"

ImageMagick/IM4J FileNotFoundException

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.

Categories

Resources