InputStreamReader throws NullPointerException when launching via cmd - java

I wrote some code to open and read the content of a csv file:
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(this.getClass().getResourceAsStream(fileName)));
String line;
try {
line = bufferedReader.readLine();
while (line != null) {
line = bufferedReader.readLine();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// close buffered reader
}
The code is working fine in unit tests, no exception is raised. However once I try to launch the program via cmd it throws a NPE coming from InputStreamReader:
Exception in thread "main" java.lang.NullPointerException
at exercise.FileLoader.loader(FileLoader.java:28)
at exercise.Application.main(Application.java:22)
The program takes actually the file name as parameter:
public static void main(String[] args) {
if (args.length > 1) {
System.out.println("Too many input arguments.");
System.exit(-1);
}
String fileName = args[0];
//here runs the method who reads the csv file above
}
Could you tell me what is happening ?

The following reads not a File on the file system, but a resource on the class path (principly read-only).
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(getClass().getResourceAsStream(fileName)));
Also the encoding is that of current platform, which might differ on another PC.
And I see no close() which probably got deleted on preparing the question.
For the file system:
Path path = Paths.get(filename);
try (BufferedReader bufferedReader =
Files.newBufferedReader(path, Charset.defaultCharset())) {
line = ...
...
} // Automatic close.
There has to be taken some care when the path is not absolute. Then it depends where the "working directory" points to, where the application is started.

I think your problem is related to the program being unable to find the file once you launch the program via cmd.
Have you tried putting the program in the same folder of the file? You could also ask for a user's input in the main so that you can provide the correct folder.

Related

BufferedReader not seeing end-of-file on StdIn when run under Eclipse

I'm reading standard input:
public static void main(String[] args) {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
for (;;) {
var line = br.readLine();
if (line == null) break;
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
System.err.println("Done.");
}
If I use this in a terminal:
java TheClass </path/to/file
... it works: the program runs to completion.
But under Eclipse, if I set the same file as standard input (Run Configurations>Common>Standard Input and output), the program reads the file but it hangs after the last line until I enter a Ctrl-D in the console window (and then terminates normally).
Also under Eclipse, if I use the file directly (FileInputStream) the file is read to the end and the program terminates immediately.
Am I missing something or is this an Eclipse problem?
Using Eclipse 2020-06 on Linux with openjdk 11.
Sounds like Eclipse bug: 513713 - In Run configuration when reading standard input from file, EOF is not issued at the end

File.delete() & File.renameTo() Not Working in Project Environment

I am trying to create an authentication system of sorts that uses a file called Users.dat to store user data. Currently, I am developing a method to remove users by rewriting the Users.dat file, omitting the user specified. The code below works in a basic environment with an all-encompassing directory containing the .java files and the Users.dat file in the same spot. The old Users.dat file is deleted and Users.dat.tmp is renamed to User.dat. (No problems here, everything works as intended).
public static boolean RemoveUser(String userName) {
// TODO remove username from Users.dat
try {
File originalFile = new File("Users.dat");
System.out.println(originalFile.getAbsolutePath());
BufferedReader read = new BufferedReader(new FileReader("Users.dat"));
String line = null;
while ((line = read.readLine()) != null) {
if (line.indexOf(userName) != -1) {
break;
}
}
String[] userInfo = line.split(", ");
if (!userName.equals(userInfo[2])) {
System.out.println("Username not found. No users removed.");
read.close();
return false;
}
File tempFile = new File(originalFile.getAbsolutePath() + ".tmp");
PrintWriter print = new PrintWriter(new FileWriter(tempFile));
String lineToRemove = line;
BufferedReader read2 = new BufferedReader(new FileReader("Users.dat"));
while ((line = read2.readLine()) != null) {
if (!line.trim().equals(lineToRemove)) {
print.println(line);
print.flush();
}
}
print.close();
read.close();
read2.close();
System.out.println(originalFile.getAbsolutePath());
originalFile.delete(); //This line is not executing correctly
tempFile.renameTo(originalFile); //Nor is this line
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
return true;
}
Users.dat file format:
Joe, Last, jlast, 58c536ed8facc2c2a293a18a48e3e120, true
Sam, sone, samsone, 2c2a293a18a48e3e12058c536ed8facc, false
Jane, Best, jbest, 293a18a48e3e12052058c536ed8facc2c, false
Andrew, Estes, Aestes, 63a490d69aa544fd1272a976014ad570, true
Test, User, tuser, 63a490d69aa544fd1272a976014ad570, true
I have two System.out.println(originalFile.getAbsolutePath()) statements, one at the beginning, one at the end to make sure the path isn't getting screwed up in the process of everything somehow.
Like I said, the code works, however, when I try to implement it in my project, it creates the Users.dat.tmp and it writes the correct data to it, but it does not delete the old Users.dat file, nor does it rename the Users.dat.tmp file to replace Users.dat. I'm certain the directory is correct, as I am literally displaying it as the code executes. I can't figure out any other reason why originalFile.delete() and tempFile.renameTo(originalFile) aren't functioning properly.
EDIT:
Using java.nio.file, I was able to produce an error message. it reads:
java.nio.file.FileSystemException: C:\Path\Users.dat: The process cannot access the file because it is being used by another process.
I don't have the file open when this error message is shown, and I don't get this error using java.nio in my testing environment mentioned at the beginning. I'm not sure what other process the message is referring to.
EDIT 2:
I tried running the code on other machines, one a Mac, the other a Windows laptop, and the code functioned on the Mac just fine, but I was still seeing the same issue on the Windows laptop.
I had the similar issue. My problem was not closing all the streams I read and written to the file. Thanks for your Edit #1, that was helpful
When you wrap
BufferedReader read = new BufferedReader(new FileReader("Users.dat"));
don't you need to close the inner readers too?
If not for the author, but for those who stambled upon this question (like me), hope this suggestion will be useful
I had an earlier function that I was calling in main that was accessing Users.dat, but I never closed the BufferredReader in that function.

Error handling in java

Am running .exe file from java code using ProcessBulider, the code I have written is given below. The .exe file takes Input.txt(placed in same directory) as input and provide 3 output file in same directory.
public void ExeternalFileProcessing() throws IOException, InterruptedException {
String executableFileName = "I:/Rod/test.exe;
ProcessBuilder processBuilderObject=new ProcessBuilder(executableFileName,"Input.txt");
File absoluteDirectory = new File("I:/Rod");
processBuilderObject.directory(absoluteDirectory);
Process process = processBuilderObject.start();
process.waitFor();
}
this process is working fine by call ExeternalFileProcessing(). Now am doing validation process, If there is any crash/.exe file doesn't run, I should get the error message how can I get error message?
Note: It would be better that error message be simple like run successful/doesn't run successful or simply true/false, so that I can put this in If condition to continue the remaining process.
You can add exception handlers to get the error message.
public void externalFileProcessing() {
String executableFileName = "I:/Rod/test.exe";
ProcessBuilder processBuilderObject = new ProcessBuilder(
executableFileName, "Input.txt");
File absoluteDirectory = new File("I:/Rod");
processBuilderObject.directory(absoluteDirectory);
try {
Process process = processBuilderObject.start();
process.waitFor();
// this code will be executed if the process works
System.out.println("works");
} catch (IOException e) {
// this code will be executed if a IOException happens "e.getMessage()" will have an error
e.printStackTrace();
} catch (InterruptedException e) {
// this code will be executed if the thread is interrupted
e.printStackTrace();
}
}
But it would be better to handle it in the calling function by put a try catch handler in the calling function and handling it there.
Is it a third party .exe or do you have access to its sources? If so, you could work with basic System outputs (for example couts to the console).
Those outputs can be redirected to your java app using something like this:
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = "";
while ((line = br.readLine()) != null) {
if(line.equals("something")) {
// do something
}
}
br.close();
This is how i do things like that and it works very well in general. But i must admit, that i can not say/garuantee, that this is THE way to do it. A more advanced approach might be the use of StreamGobbler (see Listing 4.5) to handle the outputs of the .exe.
Let me know if it helped you or not.

how to detect file has been deleted from within br.readline() loop

Related to this question
Java writing to a deleted file
only in my case i'm doing the reading. And per that comment, yes, Windows block deletes and Unix doesn't. and under unix never throws any IOException
the code is a poor-man's tail -f, where i have a java thread watching each log file in a directory. my current issue is if the file is deleted, i'm not handling it. I need to abort and start a new thread or something. I didn't even realize it was an issue, as the below code throws no exceptions under Unix
the code
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(f)));
String line = null;
while (true) {
try {
line = br.readLine();
// will return null if no lines added
} catch (IOException e) {
e.printStackTrace();
}
if (line == null) {
// sleep if no new lines added to file
Thread.sleep(1000);
} else {
// line is not null, process line
}
}
Tomorrow I'll try adding this check before the sleep, maybe is sufficient
if (!f.exists()) {
// file gone, aborting this thread
return;
}
Anyone have other ideas?
When you reach the end of a file, BufferedReader should always return a null whether it has been deleted or not. Its not something you should have to check for.
Can you show us some code because its very hard to stop the BufferedReader not returning a null?
This program
public class Main {
public static void main(String... args) throws IOException {
PrintWriter pw = new PrintWriter("file.txt");
for (int i = 0; i < 1000; i++)
pw.println("Hello World");
pw.close();
BufferedReader br = new BufferedReader(new FileReader("file.txt"));
br.readLine();
if (!new File("file.txt").delete())
throw new AssertionError("Could not delete file.");
while (br.readLine() != null) ;
br.close();
System.out.println("The end of file was reached.");
}
}
On windows prints
AssertionError: Could not delete file.
On Linux prints
The end of file was reached.
You could watch your directory using WatchService API for changes and act accordingly

Running a Binary file using Java in Ubuntu

I am trying to run a binary file, which is Genia Sequence Splitter through java code. This Binary file is type x-executable and has no extension. I can run the file in terminal by using ./geniass arg1 arg2
where arg1 is input file arg2 is output file
I want to automate this process. I tried using this code
public class geniaSSTag {
public static void geniaSS(String inputFile){
System.out.println("Input file: "+inputFile);
String[]cmd={"bash","geniass/./geniass","in.txt","out.txt"};
try {
String errOutput="";
Process process = Runtime.getRuntime().exec(cmd);
String s = "";
BufferedReader br = new BufferedReader(new InputStreamReader(process
.getInputStream()));
while ((s = br.readLine()) != null)
{
s += s + "\n";
}
System.out.println(s);
BufferedReader br2 = new BufferedReader(new InputStreamReader(process.getErrorStream()));
while (br2.ready() && (s = br2.readLine()) != null)
{
errOutput += s;
}
System.out.println(errOutput);
} catch (IOException ex) {
Logger.getLogger(geniaSSTag.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
But I get this error when I try to run
geniass/./geniass: geniass/./geniass: cannot execute binary file
How can I solve this. Any help is appreciated.
Thank you
When you run the program, is the executable relative to the program's starting directory in the manner that it lies in "./genias/genias"? Note that the "/./" doesn't do anything except waste space, as it is shorthand for "the subdirectory that links back to the current directory".
Perhaps your "genias" executable isn't in a subdirectory named "genias", or the launching program is being launched from a different directory and can't find "genias/genias" relative to it's directory.
As suggested elsewhere, you can fix this by using an absolute path in the launching command. However, sometimes this just isn't flexible enough if you want multiple copies installed.
I would try first to run the command pwd from Java to see where you actually are. Then you can change the path to your executable accordingly. I guess using the path /home/xxx/yyy/geniass would always work.
Also there is a different version of Runtime.exec() which takes a working directory as an argument.
Try:
String[]cmd={"/full/path/to/geniass","in.txt","out.txt"};
Instead

Categories