FileWriter object reference not being overwritten as expected - java

I was working with a fellow peer on a simple coding exercise and we stumbled across this issue.
The program requirements outlined that if the third command line argument was "a", the output file should be appended to, not replaced.
So, he had code something like this:
import java.io.FileWriter;
import java.io.IOException;
public class MyFileWriter {
public static void main(String[] args) {
//...
try {
FileWriter fw = new FileWriter("testfile");
if(args[2].equals("a")) {
fw = new FileWriter("testfile", true);
}
else if(args[2].equals("r")) {
fw = new FileWriter("testfile");
}
}
catch(IOException e) {
System.out.println(e.getMessage());
}
}
}
I know that initializing FileWriter before either of the if statements is redundant, but that's how it was set up. We ran it with the third command line argument being "a", and that if statement ran successfully. However, the FileWriter object was not appending to the file as was expected.
We changed the initial declaration of the FileWriter to the following:
FileWriter fw = null;
And then it worked. I figured it had to be some kind of reference or pointer issue, but why? Theoretically, the assignment operator should overwrite the value of whatever the thing points to, so even though initializing it to begin with is redundant, it should just overwrite the object entirely.
Anyone know why this was an issue? I'm just curious.

I figured it had to be some kind of reference or pointer issue, but why?
No, its a matter of your code flow and how you call the FileWriter() constructor.
The first call to FileWriter() in
try {
FileWriter fw = new FileWriter("testfile");
....
already overwrites and clears the file, before you later on create another FileWriter which was intended to append to it:
...
if(args[2].equals("a")) {
fw = new FileWriter("testfile", true); // here, "testfile" was already overwritten
}
...
Hence, effectively you are appending to an empty file.
Keep in mind that Constructors can contain any kind of program code. You do not even necessarily have to assign the "result" of the constructor call to a variable - the following would have the same effect of overwriting the file:
...
new FileWriter("testfile");
....

Related

Beginner Q: how to open a file in Java and keep it open

This is just for a simple command-line standalone program in Java.
I'd like to open a file to write to, and keep it open. I need to write formatted floats/doubles to it, in human-readable ASCII, like a CSV file.
I have tried various approaches (1) (2) (3) I have found through my favorite search engine, and they have the form:
try {
// some file handle opening sequence
}
catch ( <some exception> ) {
// do something
}
finally {
// do something else
}
(...or in the case of the third example, the file opening/writing/closing is inside a function that throws an exception.) I realize it's good programming style to make sure that you've opened a file ok, but for my purposes that's really not necessary.
Anyway the problem with the above approach is that outside of the try{} block, the filehandle is closed. I'd like to keep it open, because the kernel of my code consists of a huge loop that I go through a few 100,000 times (say), and each time through I'd like to output a single float (in ASCII) to the file.
With the above form, the only way to do that is to enclose my huge for loop inside the try{} block. Which seems silly. Alternatively, I could re-open the file every time through the loop, but that means additional logic, opening the file as a 'new' file the first time, and appending in all subsequent times.
Is there some way to open the file, keep it open to write to it occasionally, and then close it when I'm done?
Something like:
{
// open file "data.out"
}
for (i=0;i<100000;i++) {
// do a lot of stuff
//
// calculate some quantity "x"
//
// output float "x" in ASCII form, appending it to data.out
}
{
// close data.out
}
Does Java allow that? Thanks.
Of course you can simple store your FileWriter somewhere, as any other variable. You can, for example, encapsulate the whole writing logic in its own class, which offers one write method for your specified format.
But why does it seem silly? Perhaps this approach might help...
public void methodA(File myFile) throws IOException{
try ( FileWriter writer = new FileWriter( myFile ) ) {
writeTo(writer);
}
}
private void writeTo(FileWriter writer) throws IOException {
for (i=0;i<100000;i++) {
// do a lot of stuff
//
// calculate some quantity "x"
//
// output float "x" in ASCII form, appending it to data.out
}
}
This way, one method takes care of the opening/closing/exceptions, while the other method can concentrate on the important writing stuff, using the FileWriter given to it.
as you said the file is closed at the end of the try block. Possibly
the FileWriter object is created inside the try block:
(You did not post a real java code, only a pseudo code.)
Example, hope this helps
public static void main(String[] args)
{
...
BufferedWriter ofs=null; // should by outside the try block
try
{
Path logfile = Paths.set("C:\\temp\\log.log");
ofs = Files.newBufferedWriter(logfile); // new in java 8
YourWorker.doYourJob(ofs);
} catch (Exception e)
{ e.printStackTrace();
} finally
{
if (ofs!=null) { try { ofs.close(); } catch (Exception e) {} }
}
System.exit(1);
} //---------- end of main()
} //---- end of class

Cannot add new object to a set, values come from a file

I am trying to create a public instance method that takes no arguments and returns no values. It is required to get an input from a user to select a file, this part I have no issues with. The method needs to make use of the BufferReader and Scanner Objects. So that it can read the file selected. For each line that is read, a new object should be created and its instance variables set using the values found in the file.
That object that is created should then be added to a list. This is where I am having issues, it won't let me add the new object to the list. Below is my code:
public void readInEntrants()
{
String pathname = OUFileChooser.getFilename();
File aFile = new File(pathname);
Scanner bufferedScanner = null;
Set<Entrant> entrantSet = new HashSet<>();
try
{
String currentEntrantLine;
Scanner lineScanner;
bufferedScanner = new Scanner(new BufferedReader(new FileReader(aFile)));
while (bufferedScanner.hasNextLine())
{
currentEntrantLine = bufferedScanner.nextLine();
lineScanner = new Scanner(currentEntrantLine);
lineScanner.useDelimiter(" ");
currentEntrantLine = lineScanner.next();
entrantSet.add(new Entrant(currentEntrantLine)); // <----- Here is where I am having trouble. It won't let me add the new object to the class Entrant
}
}
catch (Exception anException)
{
System.out.println("Error: " + anException);
}
finally
{
try
{
bufferedScanner.close();
}
catch (Exception anException)
{
System.out.println("Error: " + anException);
}
}
return entrantSet;
}
I'm not sure what to do. Could anyone see what I am doing wrong?
Sorry for got to add that it is a compilation issue, it will not compile properly.
Use an IDE ,I bet you dont (otherwise it would mark compilation error immediatly with red -> you use return in void method ) and in this case you would see other errors.
(off: this would go to comment section however under 50reputation I am not allowed to do that. Stackoverflow should change this imo. )
First of all:
You marked function readInEntrants as public void so you can't use return inside.
You could either remove return entrantSet; instruction or change function definition to public Set<Entrant> readInEntrants.
Concerning problem you have:
Basing on comment you left on beatrice answer I think you have only parameterless constructor for 'Entrant' class, while you try to create it passing string as parameter.
new Entrant(currentEntrantLine)
What you need to do is define Entrant class constructor that accept String as it's argument. For example:
public Entrant(String dataToParse)
{
// here you parse data from string to entrant fields
}
On the side:
You use bufferedReader to read entire file line at once and that's ok, but then you define Scanner lineScanner to iterate through line elements and then use it only once.
This way for file... let's say:
One Two Three
Four Five Six
Your while loop would work like this:
Store "One Two Three" inside currentEntrantLine.
Create scanner that'll work on "One Two Three", and set it to use space as delimiter.
Use .next to "Finds and returns the next complete token" (see documentation) and then store value inside currentEntrantLine. This way contents of currentEntrantLine is "One". Not entire line.
In next iteration you would have scanner working on "Four Five Six" and "Four" as currentEntranceLine content.
It seems the constructor of entrant class does not have any argument. Pass String as an argument type in the constructor to set the String field inside the Entrant class .

hasNext code in Java

I'm having trouble opening a file. The hasNext seems to crashing with the following error java.lang.NullPointer. This is my the code that's erring out (with hasNext).
import java.io.*;
import java.util.Scanner;
public class Customers{
private Scanner opener;
public void openFile() {
try {
opener = new Scanner (new File ("customer.txt"));
} catch (Exception f) {
System.out.println("Can not read file.");
}
}
public void readFile() {
while(opener.hasNext()) {
String a = opener.next();
String b = opener.next();
String c = opener.next();
System.out.printf("%s %s %s\n", a, b, c);
}
}
public void closeFile() {
opener.close();
}
}
and this is the other class:
public class fileTest {
public static void main (String args []) {
Customers c = new Customers();
c.openFile();
c.readFile();
c.closeFile();
}
}
opener might be null as there could be an exception in opening the file
public void openFile() throws Exception{
opener = new Scanner (new File ("customer.txt"));
}
If there is any exception in opening the file, then just a message is printed and opener remains null which will lead to NPE in opener.hasNext()
You should not catch the exception instead throw the exception because if you are not able to open the file, then the code should fail and the other methods should not execute.
Your question is not clear, but you seem to be saying that opener.hasNext() is throwing an NPE.
If so, that means that opener is null. That in turn means that either you are not calling openFile() OR you are calling it but it is not working. I suspect the latter, especially since the main method does call openFile().
If the openFile() method fails to open the file (e.g. because it doesn't exist with the pathname as given), then a message is printed and opener remains null. This is probably what is happening.
The openFile() method has a number of flaws:
it is catching Exception ... which could catch other exceptions than the one(s) you are expecting.
it is not logging the stacktrace or the actual exception message
it is assuming that the problem is due to not being able to open the file ... when it could possibly be something else (in general, if not in this particular case),
once it has printed the error message, it just continues as if nothing bad had happened.
The NPE problems are then a consequence of the openFile() flaws.
Note that if you print out the actual exception message, it should tell you why the application is unable to open the file.
UPDATE
The error message customer.txt (The system cannot find the file specified) is clearly telling you that it can't find the file. The chances are that your application's current directory is not the directory that contains that file. Since you used a relative pathname, you told it it look in the current directory. The solution is to either use an absolute (full) pathname ... or make sure your application is launched with the right current directory.
Once you get past this problem, there is a problem in the way that you are reading the file. The readFile() method is assuming that it is going to be able to read multiples of 3 tokens (strings) from the input. If there is a problem with the file format, you are liable to get an (unchecked) exception. You probably should catch this exception and produce a diagnostic ... rather than assuming that nothing bad can happen.
First:Make sure your file actually exists in the disk, it is possible to create a File object even if the file does not exists.
Second:You are checkin for one element by doin opener.hasNext() and accessing next 3 elements!
When there is only one element in the list opener.hasNext() return true but you are accessing next 2 elements which are not present! hence the null pointer exception
your opener is not getting initialized that why the null pointer exception, make sure the file exists there and just try to give absolute path of the file
Check few points here:
Is your program reading the file specified?If you are using eclipse,keep your file in src folder and give path as opener = new Scanner (new File ("src/customer.txt"));
2.The second problem with your code is you are only checking once for while(opener.hasNext()) for next element and then reading three elements String a = opener.next();
String b = opener.next();
String c = opener.next(); .If there is no next element in your file you will get an exception ,check for each element before accessing it.
use this code instead:
public void readFile() {
while(opener.hasNext()) {
String a = opener.next();
System.out.printf("%s\n", a);
}
}

Picking up from where I left off when reading a file in Java

I am trying to read info from a file and create objects out of that information. Every 6 or so lines of the file is a different unit, meaning that the first set of lines are relevant to object A, the next set to object B, and so on.
I can read from the file and create my object just fine--for the first set. My problem is that I don't know how to get the reader to pick up from the spot it left off at when creating the next object...
(Note: the read() method which creates the file is part of the new object being created, not in a main() or anything like that). Here are the relevant bits of code:
The driver:
public class CSD{
public static void main (String[] argv){
Vector V=new Vector(10);
CoS jon=new CoS();
jon.display();
}//end main
}
which calls CoS, whose constructor is:
public CoS(){
try{
String fileName=getFileName();
FileReader freader=new FileReader(fileName);
BufferedReader inputFile=new BufferedReader(freader);
this.read(inputFile);
setDegree(major);
setStatus(credits);
} catch(FileNotFoundException ex){
}//end catch
}
Which calls both read() and getFileName():
public void read(BufferedReader inputFile){
try{
int n;
super.read(inputFile);
String str=inputFile.readLine();
if (str!=null){
n=Integer.parseInt(str);
setCredits(n);
str=inputFile.readLine();
setMajor(str);
}//end if
}catch(IOException ex){}
}//end method
public String getFileName() {
Scanner scan = new Scanner(System.in);
String filename;
System.out.print("Enter the file name and path ==> ");
filename = scan.nextLine();
System.out.println("");
return filename;
}
Thanks in advance, guys!
Why not use ObjectInputStream and ObjectOutputStream? Or any kind of real serialization?
javadoc: http://docs.oracle.com/javase/6/docs/api/java/io/ObjectOutputStream.html
example code: http://www.javadb.com/writing-objects-to-file-with-objectoutputstream
Basically, since you write your objects to a file and want to take care of the lines where they are located, I'll suggest a few other serialization alternatives.
One is the Object * Stream - you create a ObjectStream on a File and just write objects thru it. Later when you read, you read the objects in the reverse order you wrote them and they will come back just as you wrote them.
Another is to implement Serializable. Remember that transient keyword? Use it on fields you do not want to save to the file.
And then there's the raw "by hand" approach where you save only the things you want to save and reconstruct the objects later by passing these initialization values to their constructor. Kinda like people suggested that you make the file line a argument to the ctor :)
EDIT:
guess writing with Object*Streams requires you to implement Serializable or Externalizable.
but if the example code isn't clear enough, ask :)

which of the two is a better way of creating and destroying objects?

i have a question on lines 26 & 27:
String dumb = input.nextLine();
output.println(dumb.replaceAll(REMOVE, ADD));
i was hoping that i'd be able to shrink this down to a single line and be able to save space, so i did:
output.println(new String(input.nextLine()).replaceAll(REMOVE, ADD));
but now i'm wondering about performance. i understand that this program is quiet basic and doesn't need optimization, but i'd like to learn this.
the way i look at it, in the first scenario i'm creating a string object dumb, but once i leave the loop the object is abandoned and the JVM should clean it up, right? but does the JVM clean up the abandoned object faster than the program goes through the loop? or will there be several string objects waiting for garbage collection once the program is done?
and is my logic correct that in the second scenario the String object is created on the fly and destroyed once the program has passed through that line? and is this in fact a performance gain?
i'd appreciate it if you could clear this up for me.
thank you,
p.s. in case you are wondering about the program (i assumed it was straight forward) it takes in an input file, and output file, and two words, the program takes the input file, replaces the first word with the second and writes it into the second file. if you've actually read this far and would like to suggest ways i could make my code better, PLEASE DO SO. i'd be very grateful.
import java.io.File;
import java.util.Scanner;
import java.io.PrintWriter;
public class RW {
public static void main(String[] args) throws Exception{
String INPUT_FILE = args[0];
String OUTPUT_FILE = args[1];
String REMOVE = args[2];
String ADD = args[3];
File ifile = new File(INPUT_FILE);
File ofile = new File(OUTPUT_FILE);
if (ifile.exists() == false) {
System.out.println("the input file does not exists in the current folder");
System.out.println("please provide the input file");
System.exit(0);
}
Scanner input = new Scanner(ifile);
PrintWriter output = new PrintWriter(ofile);
while(input.hasNextLine()) {
String dumb = input.nextLine();
output.println(dumb.replaceAll(REMOVE, ADD));
}
input.close();
output.close();
}
}
The very, very first thing I'm going to say is this:
Don't worry about optimizing performance prematurely. The Java compiler is smart, it'll optimize a lot of this stuff for you, and even if it didn't you're optimizing out incredibly tiny amounts of time. The stream IO you've got going there is already running for orders of magnitude longer than the amount of time you're talking about.
What is most important is how easy the code is to understand. You've got a nice code style, going from your example, so keep that up. Which of the two code snippets is easier for someone other than you to read? That is the best option. :)
That said, here are some more specific answers to your questions:
Garbage collection will absolutely pick up objects which are instantiated inside the scope of a loop. The fact that it's instantiated inside the loop means that Java will already have marked it for clean up as soon as it fell out of scope. The next time GC runs, it will clean up all of those things which have been marked for clean up.
Creating an object inline will still create an object. The constructor is still called, memory is still allocated... Under the hood, they are really, really similar. It's just that in one case that object has a name, and in the other it doesn't. You're not going to save any real resources by combining two lines of code into one.
"input.nextLine()" already returns a String, so you don't need to wrap it in a new String(). (So yes, removing that actually will result in one less object being instantiated!)
Local Objects are eligible for GC once they go out of scope. That does not mean that GC cleans them that very moment. The eligible objects undergone a lifecycle. GC may or may not collect them immediately.
As far your program is concerned, there is nothing much to optimize except a line or two. Below is a restructured program.
import java.io.File;
import java.util.Scanner;
import java.io.PrintWriter;
public class Test {
public static void main(String[] args) throws Exception {
String INPUT_FILE = args[0];
String OUTPUT_FILE = args[1];
String REMOVE = args[2];
String ADD = args[3];
File ifile = new File(INPUT_FILE);
File ofile = new File(OUTPUT_FILE);
if (ifile.exists() == false) {
System.out.println("the input file does not exists in the current folder\nplease provide the input file");
System.exit(0);
}
Scanner input = null;
PrintWriter output = null;
try {
input = new Scanner(ifile);
output = new PrintWriter(ofile);
while (input.hasNextLine()) {
output.println(input.nextLine().replaceAll(REMOVE, ADD));
}
} finally {
if (input != null)
input.close();
if(output != null)
output.close();
}
}
}
If you arew concerned about obejct creation and performance, use a profiler to mesure your code. And keep in mind that doing new String(input.nextLine()) is totally pointless since input.nextLine() returns an immutable instance of String. So just do output.println(input.nextLine().replaceAll(REMOVE, ADD));.

Categories