Cannot run python script from java jar - java

While working in IntelliJ everything worked but after I built jar it stopped. At first, it was just me forgetting to put it in jar build config, but now after making sure it is there, I still can't run it. These are ways I try:
InputStream script = mainView.class.getResourceAsStream("vizualize3D.py");
Process process = new ProcessBuilder("python3", "-").start() ;
Process p1 = Runtime.getRuntime().exec("python3 " + script);
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec("python3 " + mainView.class.getResourceAsStream("vizualize3D.py"));
None of theme work despite having it in resources. I also tried to specify path to it in IntelliJ project and it works but only when run from IntelliJ after I start it from jar it doesn't.
Edit1:
For people that didn't understand py file is in jar file

None of the options involving you trying to execute "python3 "+script, and equivalents, will work. script is an InputStream, not a path on the file system, so simply concatenating it with a String will not give you anything meaningful. Additionally, since your script is not in its own file, and there's no simple way for the python interpreter to extract it, simply invoking it like this won't work.
What you can do, however, is to execute
python3 -
The - option here (at least on BSD-like systems) means "read from standard input, and interpret it as a script". Then, on the Java side, you can read the jar-packaged resource as a stream and pipe it to the python process's standard input.
For details on choosing the correct path for the resource, see How do I determine the correct path for FXML files, CSS files, Images, and other resources needed by my JavaFX Application?.
The following, in which the script is simply placed in the same package as the class, works for me:
PythonRunner.java:
package example.python;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
public class PythonRunner {
public static void main(String[] args) throws Exception {
String pythonInterpreter = "/usr/bin/python3" ; // default
if (args.length > 0) {
pythonInterpreter = args[0] ;
}
InputStream script = PythonRunner.class.getResourceAsStream("script.py");
Process pythonProcess = new ProcessBuilder(pythonInterpreter, "-")
.start();
// This thread reads the output from the process and
// processes it (in this case just dumps it to standard out)
new Thread(() -> {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(pythonProcess.getInputStream()))) {
for (String line ; (line = reader.readLine()) != null ;) {
System.out.println(line);
}
} catch (IOException exc) {
exc.printStackTrace();
}
}).start();
// read the script from the resource, and pipe it to the
// python process's standard input (which will be read because
// of the '-' option)
OutputStream stdin = pythonProcess.getOutputStream();
byte[] buffer = new byte[1024];
for (int read = 0 ; read >= 0 ; read = script.read(buffer)) {
stdin.write(buffer, 0, read);
}
stdin.close();
}
}
script.py:
import sys
for i in range(10):
print("Spam")
sys.exit(0)
MANIFEST.MF
Manifest-Version: 1.0
Main-Class: example.python.PythonRunner
Eclipse layout:
Jar contents and result of running:
$ jar tf runPython.jar
META-INF/MANIFEST.MF
example/python/PythonRunner.class
example/python/script.py
$ java -jar runPython.jar
Spam
Spam
Spam
Spam
Spam
Spam
Spam
Spam
Spam
Spam
$

Related

How do I print the list of files and folders in a root directory in linux using java

I am new to both Java and Linux, I was trying to use some Runtime.exec() commands that would allow my program to execute commands in Linux such as "cd /mnt/" and "ls --group-directories-first" to list files and directories contained in /mnt/ but I think I am making a problem with the execution.
I tried my code to only include the "ls --group-directories-first" and it worked like a charm, only problem was, it only listed subdirectories and files in the projects folder. I wanted to make my program go to /mnt/ first so I made my command line to a command array by using exec(String[] cmdarray) format as process1 = Runtime.getRuntime().exec(new String[]{"cd /mnt/","ls --group-directories-first"}); and when I ran it on linux, it just got executed without any printed runtime errors but also without any feedback/printed lines.
Here is my code:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class linCom {
public static void main(String args[]) {
String s;
Process p;
try {
p = Runtime.getRuntime().exec("ls --group-directories-first");
BufferedReader br = new BufferedReader(
new InputStreamReader(p.getInputStream()));
while ((s = br.readLine()) != null)
System.out.println("line: " + s);
p.waitFor();
System.out.println ("exit: " + p.exitValue());
p.destroy();
} catch (Exception e) {}
}
}
This worked and printed out:
"line: DummyFolder1
line: linCom.class
line: linCom.java
exit: 0"
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class linCom {
public static void main(String args[]) {
String s;
Process p;
try {
p = Runtime.getRuntime().exec(new String[]{"cd /mnt/","ls --group-directories-first"});
BufferedReader br = new BufferedReader(
new InputStreamReader(p.getInputStream()));
while ((s = br.readLine()) != null)
System.out.println("line: " + s);
p.waitFor();
System.out.println ("exit: " + p.exitValue());
p.destroy();
} catch (Exception e) {}
}
}
This just got executed with no printed lines.
I expected my program to just go to the /mnt/ directory and print out subdirectories and files on there, but it just got executed with no visible runtime errors and no printed lines.
I have looked at other entries but could not find any answer to my problem.
EDIT: I changed "no errors" with "no error messages" to make it clear that if program had any errors, I did not get any feedback about it.
Here's where the UNIX process model can be confusing.
What you have tries to run the program named cd /mnt/ with the first parameter of ls --group-directories-first . Unix programs can be named anything (they're just filenames) but there's no program named cd /mnt. And anyway, the cd operation is actually performed by a shell, not as a forked/execed program.
You hope to run this shell command from your Java program: cd /mnt/; ls --group-directories-first . The trouble is, Java's .exec() method does not give you a shell, so shell commands don't work.
You can try this instead. It's like running the shell command
/bin/sh -c "cd /mnt/; ls --group-directories-first"
With this, you start a shell, then tell it to run -cthe command you want.
Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh",
"-c",
"cd /mnt/; ls --group-directories-first"});
But it's quite dependent on the machine where your Java program runs, so be careful.
Reference: How to invoke a Linux shell command from Java
Do not use an external process just to list files. Java has plenty of ways to do that. All of them are in the Files class. For example:
Path dir = Paths.get("/mnt");
try (Stream<Path> files = Files.list(dir).sorted(
Comparator.comparing((Path p) -> !Files.isDirectory(p))
.thenComparing(Comparator.naturalOrder()))) {
files.forEach(System.out::println);
}
Do you really need to use Runtime.exec()comands? That would make your code platafform dependent.
You could use File.listFiles():
File folder = new File("/mnt");
for (File f : folder.listFiles()) {
System.out.println(f.getName());
}
That would make the code less plataform dependent

java.lang.Runtime exception "Cannot run program"

I am getting an exception like java.io.IOException: Cannot run program cat /home/talha/* | grep -c TEXT_TO_SEARCH": error=2, No such file or directory while executing the command below despite that there are no issues when I execute the same command through the terminal. I need to execute and return the output of the command below:
cat /home/talha/* | grep -c TEXT_TO_SEARCH
Here is the method used to execute commands using Runtime class:
public static String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
Runtime.exec does not use a shell (like, say, /bin/bash); it passes the command directly to the operating system. This means wildcards like * and pipes (|) will not be understood, since cat (like all Unix commands) does not do any parsing of those characters. You need to use something like
p = new ProcessBuilder("bash", "-c", command).start();
or, if for some bizarre reason you need to stick to using the obsolete Runtime.exec methods:
p = Runtime.getRuntime().exec(new String[] { "bash", "-c", command });
If you are only running that cat/grep command, you should consider abandoning the use of an external process, since Java code can easily traverse a directory, read lines from each file, and match them against a regular expression:
Pattern pattern = Pattern.compile("TEXT_TO_SEARCH");
Charset charset = Charset.defaultCharset();
long count = 0;
try (DirectoryStream<Path> dir =
Files.newDirectoryStream(Paths.get("/home/talha"))) {
for (Path file : dir) {
count += Files.lines(file, charset).filter(pattern.asPredicate()).count();
}
}
Update: To recursively read all files in a tree, use Files.walk:
try (Stream<Path> tree =
Files.walk(Paths.get("/home/talha")).filter(Files::isReadable)) {
Iterator<Path> i = tree.iterator();
while (i.hasNext()) {
Path file = i.next();
try (Stream<String> lines = Files.lines(file, charset)) {
count += lines.filter(pattern.asPredicate()).count();
}
};
}
$PATH is an environment variable that tells the system where to search for executable programs (it's a list of directories separated by colons). It is usually set in your .bashrc or .cshrc file but this is only loaded when you log in. When Java runs, $PATH is likely not set because the rc file is not executed automatically, so the system can't find programs without specifying exactly where they are. Try using /bin/cat or /usr/bin/cat instead of just cat and see if it works. If it does, $PATH is your problem. You can add $PATH=/bin:/usr/bin to your script or just leave it with the directory name specified (e.g. /bin/cat).
Just because you can execute it in a login session doesn't mean it will work the same when a daemon like your Java program runs. You have to know what's in your .bashrc or .cshrc file and even sometimes how the system file is written (/etc/bashrc) in order to know how to write a script that runs under a daemon. Another consideration is that daemons often run under the context of a different user, and that throws things off, too.

How to Delete first n lines in a Text file using a batch file (on Windows)

I have various amounts of text files that need to have the first 26 lines deleted. I have tried the below bat but it doesn't want to even finish the first text file. The files are named data (1).txt, data (2).txt, data (3).txt, ... etc.
At first I tried...
more +26 "data (1).txt" > "data (1).txt.new"
move /y "data (1).txt.new" "data (1).txt"
This worked but it would be extremely time consuming to change each number seeing as I have ~100 text files.
So then tried to do the below.
for %%f in (*.txt) do (
more +26 "%%f" > "%%f.new"
move /y "%%f.new" "%%f")
To me it seems like this should work but it's not, it just pulls up the command line and stalls on the first file, it does create the "NEW" file but looks like it only copied half of the original text file. The files are anywhere from 1MB to ~300MB each.
So my question is simple.. What am I doing wrong and can anyone provide help/tips?
UPDATE
So I've been continuing to play with the second option and it seems to work for files up to ~125MB anything over that and it just pauses and doesn't complete the operation. Not sure if there is a fix for that or possibly a better option then using a batch file. Again any help is appreciated.
UPDATE
I was able to get what I was looking for through JAVA.
sadd
import java.io.bufferedreader;
import java.io.file;
import java.io.filereader;
import java.io.filewriter;
public class cleanfiles {
public static void main(string[] args) throws exception {
string currdir = system.getproperty("user.dir");
file inputdir = new file(currdir + file.separator + "input" + file.separator);
file[] inputfiles = inputdir.listfiles();
String outputdir = currdir + file.separator + "output" + file.separator;
for (file inputfile : inputfiles) {
if (inputfile.getabsolutepath().endswith(".txt") == false) {continue; }
file outputfile = new file(outputdir + inputfile.getname() + ".csv");
bufferedreader reader = null;
try {
reader = new bufferedreader(new filereader(inputfile));
writer = new filewriter(outputfile);
string line;
while ((line = reader.readline()) !=null) {
if (line.startswith("Point")) {
writer.append(line);
writer.append("\r\n");
break;
}
}
while ((line = reader.readline()) !=null) {
writer.append(line);
writer.append("\r\n");
}
} catch (exception e) {
} finally {
try {
reader.close();
writer.flush();
writer.close();
} catch (exception e) {}
}
}
}
}
I recommend using sed for Windows. You'll need the binaries and the dependencies linked from that page. Then you can just sed "1,26d" infile >outfile in a for loop from the command line to delete the first 26 lines of your files. No batch file needed.
for %I in (*.txt) do (sed "1,26d" "%I" >"%I.1" && move /y "%I.1" "%I")
Note: There is a -i switch for gnuwin32 sed (for inline processing) which would make the syntax a bit simpler, but last time I tried it it left a garbage file for each real file it processed. I recommend not using it.
I know from painful experience that using a stream processing application to handle large text files is MUCH faster than batch script trickery and for /f loops.
If you want to avoid using gnuwin32 sed and would prefer to use powershell, see this question's accepted answer for a worthwhile method to try. No clue whether it'd be as fast or faster than sed, though. Bill_Stewart seems enthusiastic about it. :)
If you notice the last line of your output file, you'll notice the limitation of your approach. When the number of lines exceed ~65535, MORE hangs, waiting for a key press from the user.
You can use a for loop instead:
for %%I in (*.txt) do for /f "delims=, tokens=* skip=26" %%x in (%%I) do echo %%x >> "%%I.new"

How to execute "less" with paging from a Java console application?

I need to execute the less command, with paging, from my Java console application. However, the only method I found to execute external commands is Runtime.getRuntime().exec(), which requires me to write/read input/output via streams. So commands like cat work (and less does in fact act like cat), but I need the paging functionality.
In C, I'd use system(). In Ruby, Kernel.exec does the job.
Is there any way to get this done in Java?
When you execute an external process with Runtime.exec() its standard input and output streams are not connected to the terminal from which you are running the Java program. You can use shell redirection to connect it, but first you need to know what terminal to use. There is no way to find the terminal using the standard API but probably you can find an open source library that does it.
To see that it can be done, this program opens itself in less:
public class Test {
public static void main(String[] args) throws Exception {
Process p = Runtime.getRuntime().exec(
new String[] {"sh", "-c",
"less Test.java < "+args[0] + " > "+args[0]});
System.out.println("=> "+p.waitFor());
}
}
To run it you should use java Test $(tty). The tty program prints the name of the terminal connected to its stdin.
I'm not too sure about the portability of this solution; at least it works on Linux.
List item
The following program will work, initially it prints 10 lines , then press enter it will print next line till end of the file.
run program like
java Less $fileName
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;
public class Less
{
public static void main(String args[]) throws IOException
{
FileReader reader = new FileReader(args[0]);
BufferedReader buff = new BufferedReader(reader);
String readLine;
int lineCount = 0;
while ((readLine = buff.readLine()) != null)
{
System.out.println(readLine);
lineCount++;
if (lineCount > 10)
{
Scanner scanner = new Scanner(System.in);
scanner.nextLine();
}
}
}
}

Better way of opening a Document from Java?

I've been using the following code to open Office Documents, PDF, etc. on my windows machines using Java and it's working fine, except for some reason when a filename has embedded it within it multiple contiguous spaces like "File[SPACE][SPACE]Test.doc".
How can I make this work? I'm not averse to canning the whole piece of code... but I'd rather not replace it with a third party library that calls JNI.
public static void openDocument(String path) throws IOException {
// Make forward slashes backslashes (for windows)
// Double quote any path segments with spaces in them
path = path.replace("/", "\\").replaceAll(
"\\\\([^\\\\\\\\\"]* [^\\\\\\\\\"]*)", "\\\\\\\"$1\"");
String command = "C:\\Windows\\System32\\cmd.exe /c start " + path + "";
Runtime.getRuntime().exec(command);
}
EDIT: When I run it with the errant file windows complains about finding the file. But... when I run the command line directly from the command line it runs just fine.
If you are using Java 6 you can just use the open method of java.awt.Desktop to launch the file using the default application for the current platform.
Not sure if this will help you much... I use java 1.5+'s ProcessBuilder to launch external shell scripts in a java program. Basically I do the following: ( although this may not apply because you don't want to capture the commands output; you actually wanna fire up the document - but, maybe this will spark something that you can use )
List<String> command = new ArrayList<String>();
command.add(someExecutable);
command.add(someArguemnt0);
command.add(someArgument1);
command.add(someArgument2);
ProcessBuilder builder = new ProcessBuilder(command);
try {
final Process process = builder.start();
...
} catch (IOException ioe) {}
The issue may be the "start" command you are using, rather than your file name parsing. For example, this seems to work well on my WinXP machine (using JDK 1.5)
import java.io.IOException;
import java.io.File;
public class test {
public static void openDocument(String path) throws IOException {
path = "\"" + path + "\"";
File f = new File( path );
String command = "C:\\Windows\\System32\\cmd.exe /c " + f.getPath() + "";
Runtime.getRuntime().exec(command);
}
public static void main( String[] argv ) {
test thisApp = new test();
try {
thisApp.openDocument( "c:\\so\\My Doc.doc");
}
catch( IOException e ) {
e.printStackTrace();
}
}
}

Categories