I would like to use the rar.exe path in Java. This is needed to unpack rar files from within my Java application without using a library.
I figured I'd require the user to add the program files folder for Winrar to the PATH system variable.
All I need to know now is how to get the full path to the rar.exe file.
What I've got now is this:
//Split all paths
String[] paths = System.getenv("Path").split(";");
for(String value : paths)
{
if(value.endsWith("Winrar"))
System.out.println(value);
}
However, there is no way of me knowing if the user installed Winrar to say C:\Programfiles\Winrarstuff. Is there a way to get the location of rar.exe, or do I have to manually scan every folder in the Path string for the location?
You can use where on Windows Server 2003+ which is roughly equivalent to which in *nix, however you can get similar behavior for other windows environments using the code found here: https://stackoverflow.com/a/304441/1427161
When the path to rar.exe is in the PATH environment variable, you can simply invoke rar.exe from any file location. That means you can also call it via Runtime.exec(...). If the return code is other than 0, the process cannot be started, e.g. because Winrar is not installed:
public static boolean checkRar() {
Process proc = Runtime.getRuntime().exec("cmd /c rar.exe");
try (BufferedReader reader =
new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
// parse line e.g. to get version number
}
}
return (proc.waitFor() == 0);
}
Related
This question already has answers here:
How to do URL decoding in Java?
(11 answers)
How to get the current working directory in Java?
(26 answers)
Closed 2 years ago.
In my program I did
File jarFile = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath());
execPath = String.valueOf(jarFile.getParentFile());
To get the execPath = to the path of the current execution (where the final .exe program is). Wich is an attribute of my main class, that I use to do some files manipulation and reading.
But,
When running the program in some folders with spaces or accents the value of execPath is replaced by %number like bellow
C:\Users\Hugo\OneDrive%20-%20Funda%c3%a7%c3%a3o%20para%20Inova%c3%a7%c3%b5es%20Tecnol%c3%b3gicas%20-%20FITec\Redes\AutoComRouter\
Where
OneDrive%20-%20Funda%c3%a7%c3%a3o%20para%20Inova%c3%a7%c3%b5es%20Tecnol%c3%b3gicas%20-%20FITec
should be
OneDrive - Fundação para Inovações Tecnológicas - FITec
I wonder if its possible to get rid of this annoying replacement for the my execPath attribute.
Do not call the URL.getPath() method. It does not return a valid filename, as you are now seeing. It just returns the path portion of the URL—the part after the scheme and host—with all percent escapes intact.
The correct way to convert a URL to a File is by converting it to a URI, then constructing a File from that URI.
So, the proper code would look like this:
CodeSource source = Main.class.getProtectionDomain().getCodeSource();
if (source != null) {
try {
File jarFile = new File(source.getLocation().toURI());
execPath = String.valueOf(jarFile.getParentFile());
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
Notice the check for null. The code source can be null, depending on how much information a ClassLoader is willing and able to impart to the ProtectionDomain it creates. This means that trying to find the location of a .jar file at runtime is not reliable.
If you want to bundle native executables with a .jar file, here are some more reliable options:
Include a script (batch file for Windows, shell script for other systems) with your .jar file that passes a system property to the program, which contains the location of the executables.
Bundle the executables inside the .jar file, and at runtime, copy them to temporary files and make them executable.
The first approach would use the system to determine the directory, since that is reliable, and would pass it to the program. For instance, in Windows:
set execdir=%~dp0..\..
javaw.exe "-Dexecutable.dir=%here%" -jar MyApplication.jar
In Linux:
execdir=`dirname $0`/..
java "-Dexecutable.dir=$execdir" -jar MyApplication.jar
The second approach would require creating your .jar file with the executables inside it, then copying them outside the .jar when you want to run them:
Path execDir = Files.createTempDirectory(null);
execPath = execDir.toString();
String[] executables;
String os = System.getProperty("os.name");
if (os.contains("Windows")) {
executables = new String[] {
"windows/foo.exe", "windows/bar.exe", "windows/baz.exe"
};
} else if (os.contains("Mac")) {
executables = new String[] {
"mac/foo", "mac/bar", "mac/baz"
};
} else {
executables = new String[] {
"linux/foo", "linux/bar", "linux/baz"
};
}
for (String executable : executables) {
String baseName = executable.substring(executable.lastIndexOf('/') + 1);
Path newFile = execDir.resolve(baseName);
try (InputStream executable =
Main.class.getResourceAsStream(executable)) {
Files.copy(executable, newFile);
}
if (Files.getFileStore(newFile).supportsFileAttributeView(
PosixFileAttributeView.class)) {
Set<PosixFilePermission> perms =
Files.getPosixFilePermissions(newFile);
perms.add(PosixFilePermission.OWNER_EXECUTE);
Files.setPosixFilePermissions(newFile, perms);
}
}
I am writing a java application, in which I am automatically importing external csv files in background to do the computation. But the problem is that I am using "absolute" file path in my java program, the generated jar file will not work in another computer. Is there anyway in java to use a kind of "working directory path" so that I can still run the jar file in another computer as long as I put the csv files I'd like to import in the same folder with the jar file?
Thanks!
You can read a file using its name like
try (BufferedReader br = new BufferedReader(new FileReader("text.txt"))) {
String line;
while ((line=br.readLine())!=null) {
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
Here text.txt should be in the same working directory where the jar was executed.
You can also read the directory name from the command line, using the command line arguments like
public static void main(String[] args) {
//check if there were any command line arguments
if (args.length > 0) {
// args[0] is the first command line argument unlike C where args[0] would give u the executable's name
} else {
System.err.println("Usage: java -jar <jar_name> [directory_names..]");
}
}
You can also have a configuration file such as a properties file to read the directory names.
new File(".") give you the relative path
you can write relative path like that :
File file = new File(".\\CSVs\\myfile.csv");
System.getProperty("user.dir") will return you the working directory.
System.getProperty("user.dir")+"\\myfile.txt"
More informations here :system properties, oracle docs
I'm trying to unpack/extract an archive, which is supplied in my program, containing binaries.
The copy from within the jar to the file works just fine, but when I try to extract the zip, it returns unexpectedly and only copies half of a file, and ignores the other file completely.
Here's a bit more detailed description:
I'm trying to unzip an archive copied to a folder, from within the program's .jar.
The program I'm using to unzip is "unzip" (comes with Linux).
The command used to extract is:
unzip -o <file>.zip
which is exactly what I'm using in following code:
ProcessBuilder process = new ProcessBuilder();
process.command("unzip", "-o", adb_tools.toString());
process.redirectErrorStream(true);
Process pr = process.start();
String line;
BufferedReader processReader = new BufferedReader(new InputStreamReader(pr.getInputStream()));
while ((line = processReader.readLine()) != null)
log(Level.INFO, "Extracting Android Debugging Bridge: " + line, true);
log(Level.INFO, "Android Debugging Bridge has been extracted and installed to system. Marking files as executable...", true);
pr.destroy();
processReader.close();
When I use the command directly via the Terminal, everything works fine, both files are extracted and inflated, and are executable, however, as mentioned above, when I use the command in Java, only one file gets copied (and even that only goes half way), and the other file is completely ignored.
How can I fix this problem, and prevent this happening again, with different programs?
Thanks in advance!
If you need to do a common task in Java, there is always a library out there which does what you need better than yourself. So use an external library for unzipping. Check here:
What is a good Java library to zip/unzip files?
It looks like you can use zip4j like this (from djangofan's answer):
public static void unzip(){
String source = "some/compressed/file.zip";
String destination = "some/destination/folder";
String password = "password";
try {
ZipFile zipFile = new ZipFile(source);
if (zipFile.isEncrypted()) {
zipFile.setPassword(password);
}
zipFile.extractAll(destination);
} catch (ZipException e) {
e.printStackTrace();
}
}
This is what my file looks like:
IDENTIFICATION::HARD::Should We appreciate Art?::Yes
MULTIPLECHOICE::HARD::Which of the FF is not an era of Art?::Bayutism::Digitalism,Somethingism,Retardism,Bayutism
IDENTIFICATION::HARD::What is Chris Browns Greatest Hit?::Rihanna
And I am reading the file like this
public void openQBankFile(){
try{
BufferedReader in = new BufferedReader(new FileReader(qbank.getAbsolutePath()));
String desc;
while((desc = in.readLine()) != null){
qbank_cont.add(desc);
}
in.close();
}catch(FileNotFoundException fnfe){
System.out.println("Question Repository Could Not Be Found");
return;
}catch(IOException ioe){
ioe.printStackTrace();
}
}
This where I get the contents of the arrayList
public static void main(String[] args){
CreateQuiz cq = new CreateQuiz(new File("./quiz/HUM101.quiz"),new File("./qbank/HUM101.qbank"));
cq.openQBankFile();
cq.filterQuestions(3, "HARD");
System.out.println(cq.qbank_cont.get(0));
}
And this is how I add it
public void filterQuestions(int numOfItems, String difficulty){
List<String> qt_diff = new ArrayList<String>();
for(int i = 0; i< qbank_cont.size();i++){
qt_diff.add(qbank_cont.get(i));
}
}
And I will store it inside an arrayList. but when I store it in arraylist it will just insert the whole text. Not Line per line. (I am using arrayList.get(0))
The root of your problem seems to be that you don't understand how Java deals with relative pathnames.
Here's what the File javadoc says:
On UNIX systems, a relative pathname is made absolute by resolving it against the current user directory. On Microsoft Windows systems, a relative pathname is made absolute by resolving it against the current directory of the drive named by the pathname, if any; if not, it is resolved against the current user directory.
The "current user directory" means the current directory that was in force when the application was launched. That depends on how the application was launched. For instance, if you launch from a command shell using java, the current directory will be the shell's current directory. But if you use a launch wrapper script, it may cd to somewhere else before launching the JVM. And so on.
But the bottom line is that if you are going to use relative paths, you need to have the right current directory.
Incidentally, when the JVM starts, the absolute path of the current directory is places in the System Properties object. You can read the property to find out what the current directory is, but changing the property does NOT change the way that relative paths are resolved by the File API and friends. AFAIK, there is no way that a pure Java application can reliably change its own current directory.
Im trying to write a program to read a text file through args but when i run it, it always says the file can't be found even though i placed it inside the same folder as the main.java that im running.
Does anyone know the solution to my problem or a better way of reading a text file?
Do not use relative paths in java.io.File.
It will become relative to the current working directory which is dependent on the way how you run the application which in turn is not controllable from inside your application. It will only lead to portability trouble. If you run it from inside Eclipse, the path will be relative to /path/to/eclipse/workspace/projectname. If you run it from inside command console, it will be relative to currently opened folder (even though when you run the code by absolute path!). If you run it by doubleclicking the JAR, it will be relative to the root folder of the JAR. If you run it in a webserver, it will be relative to the /path/to/webserver/binaries. Etcetera.
Always use absolute paths in java.io.File, no excuses.
For best portability and less headache with absolute paths, just place the file in a path covered by the runtime classpath (or add its path to the runtime classpath). This way you can get the file by Class#getResource() or its content by Class#getResourceAsStream(). If it's in the same folder (package) as your current class, then it's already in the classpath. To access it, just do:
public MyClass() {
URL url = getClass().getResource("filename.txt");
File file = new File(url.getPath());
InputStream input = new FileInputStream(file);
// ...
}
or
public MyClass() {
InputStream input = getClass().getResourceAsStream("filename.txt");
// ...
}
Try giving an absolute path to the filename.
Also, post the code so that we can see what exactly you're trying.
When you are opening a file with a relative file name in Java (and in general) it opens it relative to the working directory.
you can find the current working directory of your process using
String workindDir = new File(".").getAbsoultePath()
Make sure you are running your program from the correct directory (or change the file name so that it will be relative to where you are running it from).
If you're using Eclipse (or a similar IDE), the problem arises from the fact that your program is run from a few directories above where the actual source is located. Try moving your file up a level or two in the project tree.
Check out this question for more detail.
The simplest solution is to create a new file, then see where the output file is. That is the correct place to put your input file into.
If you put the file and the class working with it under same package can you use this:
Class A {
void readFile (String fileName) {
Url tmp = A.class.getResource (fileName);
// Or Url tmp = this.getClass().getResource (fileName);
File tmpFile = File (tmp);
if (tmpFile.exists())
System.out.print("I found the file.")
}
}
It will help if you read about classloaders.
say I have a text file input.txt which is located on the desktop
and input.txt has the following content
i came
i saw
i left
and below is the java code for reading that text file
public class ReadInputFromTextFile {
public static void main(String[] args) throws Exception
{
File file = new File(
"/Users/viveksingh/desktop/input.txt");
BufferedReader br
= new BufferedReader(new FileReader(file));
String st;
while ((st = br.readLine()) != null)
System.out.println(st);
}
}
output on the console:
i came
i saw
i left