Hi guys,
Today I had a look at files and therefore I’d like to create a GUI application that allows me to type a sentence or a word and store it to a text file. The reason for this is that, when I come across an interesting word or sentence I like to keep it somewhere for future reference, which means that the new word/sentence needs to be appended at the end of the file, without overwriting anything. It should also allow for multiple languages, but I don’t see that being a problem.
Following from other applications I developed, and the advices kindly given, I’ll leave the GUI as a last thing (will do it with GridBagLayout of course), so I’ll first create an application that takes a sentence/word as a hardcoded string.
The way I envisage this, providing you guys think it is a good idea, is to have a JTextArea that takes the sentence and then an action button (Save) that will allow the application to save the input to a text file.
I’ve read a bit about Sequential-access text files and object serialization. I’m a bit torn between one and the other, and here is why: I don’t really need to amend the sentence/words I write, the idea is that, I write them to file and they are there for when I want to open the file and take a look at them, but then again, what happens if I make a mistake, misspell a word and so on? Wouldn’t I need to amend it?
My understanding is that with sequential access you can’t amend things, you can only re-write the whole file whereas with object serialization you can.
So, what do you guys suggest? Do you have any advice as to how to build it?
thanks
How big do you see this file getting? If it will always fit in memory (say just a few hundred meg) then you can do all the appending editing or whatever in memory and re-write the whole thing at shutdown (and at regular intervals). You can get an awful lot of text in 100Meg - even at a skilled typist's 10 char/second that's like a year of non-stop 40 hours a week typing :)
If its going to be too big and you don't need to edit existing data use a sequential file in append mode. In any case if its just text then why use object serialisation? Just write the text.
If its too big and you want editing you could use a random access file and overwrite the old entry with a deleted flag, then append the revised entry, but personally i would consider a proper database.
But suppose you want to tag entries with some meta-data (date created, language, source URL, keywords etc etc)? In memory its still easy, just create an Entry class with appropriate attributes. But if its too big you definitely need a proper database.
thanks. I don't envisage it to get too big, in fact, it will never go past a few MB to be honest, I mean for me it is more a test than anything, I don't see myself using that application every tme, it's just for the sake of building it really.
For me sequential or serialization is the same, in the sense that, I've never used any of them, so I'll just go with whatever you guys think it's best, happy to go for sequential access, if it is better for text only.
A database isn't an option now, because, even if I've worked with databases before, it was in a different setting (ASP.NET) and I haven't got to the "databases with java" part as yet :-)
I don't even need to tag the entries, it will literally be just text, each word/sentence will occupy its own space, then a new line feed and the new sentence/word, and so on, it will be that simple.
OK, so start to build it then.
Right, I think I'm having some issues with possible exceptions in my code as the compiler is complaning.
It seems like there are an awful lot of ways to write things to file, so I guess I just picked one and went for it. Essentially, I believe I created a file, got the input from the keyboard and attempted to write that to file. Here is the code:
/*SentenceRecorder.java
takes a sentence or word as input and saves it on text file. Every new word/sentence is appended at the end of the file
*/
import java.io.File;
import java.util.Scanner;
import java.io.FileWriter;
import java.lang.SecurityException;//if no permission to write to file
import java.io.FileNotFoundException;//if the file can't be created
public class SentenceRecorder{
private Scanner input;
private String stringInput;
private String filePath;
private File file;
private FileWriter fileWriter;
/* private String string1;
private String string2; */
public SentenceRecorder(){
input = new Scanner(System.in);
filePath = "C:/sample.txt";
try{
file = new File(filePath);
}
catch(SecurityException securityException){//if you don't have write access
System.err.println("You don't have write access to this file");
System.exit(1);
}
catch(FileNotFoundException fileNotFoundException){
System.err.println("Error opening or creating the file");
System.exit(1);
}
System.out.printf("Enter your sentence");
while(input.hasNext()){
stringInput = input.nextLine();
fileWriter = new FileWriter(file,true);
fileWriter.append(stringInput);
}
}//end of constructor
public void CloseFile(){
fileWriter.close();
}//closeFile
}//end of SentenceRecorder
The compiler is saying:
G:\JAVA\GUI\2015\createFrames\files>javac *.java
SentenceRecorder.java:27: error: exception FileNotFoundException is never thrown in body of corresponding try statement
catch(FileNotFoundException fileNotFoundException){
^
SentenceRecorder.java:34: error: unreported exception IOException; must be caught or declared to be thrown
fileWriter = new FileWriter(file,true);
^
SentenceRecorder.java:35: error: unreported exception IOException; must be caught or declared to be thrown
fileWriter.append(stringInput);
^
SentenceRecorder.java:39: error: unreported exception IOException; must be caught or declared to be thrown
fileWriter.close();
^
4 errors
Why are the exceptions never thrown? I mean this line file = new File(filePath);
is effectively opning the file isn't it, so that's where the exceptions may occur...
/*SentenceRecorderTest.java*/
public class SentenceRecorderTest{
public static void main(String[] args){
SentenceRecorder sentenceRecorder = new SentenceRecorder();
sentenceRecorder.CloseFile();
}
}
No. new File(...)
does not do anything at the system level, it just creates a Java File object, and therefore can't throw I/O related exceptions. It's not until you try to use that file that any system file activity happens and exceptions can be thrown.
The other three errors are self-explanatory.
Hi thanks, sorry for the slow reply, been busy at work.
As for the other exception, got to admit I haven't come across it in the examples I've looked at, and they all work OK. Strange. In any case, I've looked that up, and it's just a general exception.
I've added this to the import declarations import java.io.IOException;
and changed the code to this:
/*SentenceRecorder.java
takes a sentence or word as input and saves it on text file. Every new word/sentence is appended at the end of the file
*/
import java.io.File;
import java.util.Scanner;
import java.io.FileWriter;
import java.lang.SecurityException;//if no permission to write to file
import java.io.FileNotFoundException;//if the file can't be created
import java.io.IOException;
public class SentenceRecorder{
private Scanner input;
private String stringInput;
private String filePath;
private File file;
private FileWriter fileWriter;
/* private String string1;
private String string2; */
public SentenceRecorder(){
input = new Scanner(System.in);
filePath = "C:/sample.txt";
file = new File(filePath);
System.out.printf("Enter your sentence");
while(input.hasNext()){
stringInput = input.nextLine();
try{
fileWriter = new FileWriter(file,true);
}
catch(SecurityException securityException){//if you don't have write access
System.err.println("You don't have write access to this file");
System.exit(1);
}
catch(FileNotFoundException fileNotFoundException){
System.err.println("Error opening or creating the file");
System.exit(1);
}
catch(IOException ioexception){
System.err.println("General Error with IO");
System.exit(1);
}
try{
fileWriter.append(stringInput);
}
catch(IOException ioexception){
System.err.println("General Error with IO");
System.exit(1);
}
}
}//end of constructor
public void CloseFile(){
try{
fileWriter.close();
}
catch(IOException ioexception){
System.err.println("General Error with IO");
System.exit(1);
}
}//closeFile
}//end of SentenceRecorder
Funny thing is that the compiler wanted me to add a general exception pretty much everywhere, and thinking about it, it's not self-explanatory to me. Why do I have to do that considering that it's just a general exception rather then adding it to fileWriter = new FileWriter(file,true);
only ?
In any case, I run the program, it compiles OK now but but...it can't open the file. Is that because, you reckon, I 'm trying to create a file in C:/?
Here is the error:
G:\JAVA\GUI\2015\createFrames\files>java SentenceRecorderTest
Enter your sentenceThis is my sentence
Error opening or creating the file
G:\JAVA\GUI\2015\createFrames\files>
Also, as a side note, I just realized something. At the moment I'm using windows, so C:/ should be acceptable, but I often find myself swapping between ubuntu and window and obviously I can't save a file in C, so what should I change the string to if I compile this program in Ubuntu
In all your catch blocks call printStackTrace() to get full info on the exact error.
Use System Properties to get the user's home or working dir, and use that for your file(s). It works appropriately in all supported OSs https://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html
OK, sorted. Basically I replaced the string filePath = "C:/sample.txt";
with filePath = "sample.txt";
and that does the trick. Just realised that this saves the file on the same directory where the application resides, so this will also guarantee support across platform as there are no file separators or full paths involved.
Just one more thing.
I run the application and it kind works but not in every single scenario. Here a a couple of runs.
G:\JAVA\GUI\2015\createFrames\files>java SentenceRecorderTest
Enter your sentence
Sentence 1
^Z
G:\JAVA\GUI\2015\createFrames\files>
This worked. The file now contains "Sentence 1".
Another round (without recompiling the application), and here the problems are evident:
G:\JAVA\GUI\2015\createFrames\files>java SentenceRecorderTest
Enter your sentence
Sentence 2
Sentence 3
^Z
G:\JAVA\GUI\2015\createFrames\files>
The file should now contain all the 3 sentences but in fact it has only:
Sentence 1Sentence 3
So "sentence 2" is lost, overwritten by sentence 3. Is that normal behaviour? What I did was to input the first sentence, then pressed Enter and I had a new empty line, then I input the second sentence ("Sentence 3") and press Enter again but I've lost the previous input and I'm not sure why that is.
Also, I want every sentence appended to the file to be on a separate line, so I amended fileWriter.append(stringInput);
to be fileWriter.append(stringInput + "\n");
but no joy. I checked the API and one of the constructors is append(String str)
so that should work shouldn't it?
So 2 issues:
-lost input
-input on separate lines
It looks like you create a new FileWriter for each line in the input (loop starting line 24), all competing to write to the same output and corrupting each other. That's a msitake, just create one filewriter at the beginning and use that for all the lines.
The file is going to the current working directory, which happens to be where the app is because that's how you're running it. Depending on how the app is run that will often NOT be the case, and you may get unpredictable crashes. See my previous post, and use the user's home or working dir. It's just one more line of code.
The file is going to the current working directory, which happens to be where the app is because that's how you're running it.
Ok thanks for clarifying that.
So, amendments done. Now I find the current directory and create the file in that directory. I've also amended the fileWriter issue, now I understand what a stupid mistake I was making.
But I still have an issue: the string entered are rendered on the same line as opposed to be on separate lines. I had a look at the API for nexLine()
which is what I'm using and says that "This method returns the rest of the current line, excluding any line separator at the end. "
So rather than
while(input.hasNext()){
stringInput = input.nextLine();
try{
fileWriter.append(stringInput + " " + "\n");
}
I tried
while(input.hasNext()){
stringInput = input.nextLine();
try{
fileWriter.append( " " + "\n" + stringInput);
}
(I wouldn't want to have an empty line to start with, but I thought I'd just truy anyway), but no difference. What would I ned to use to include the /n in the string then?
Here are the amendments you suggested to the constructor:
public SentenceRecorder(){
workingDir = System.getProperty("user.dir");
//System.out.println("workingDir is " + workingDir);
input = new Scanner(System.in);
filePath = workingDir + "\\sample.txt";
//filePath = "G:\JAVA\GUI\2015\createFrames\files";
file = new File(filePath);
System.out.printf("Enter your sentence or end of file - ctrl+z or Enter+ctrl+d\n");
try{
fileWriter = new FileWriter(file,true);
}
catch(SecurityException securityException){//if you don't have write access
System.err.println("You don't have write access to this file");
System.exit(1);
}
catch(FileNotFoundException fileNotFoundException){
System.err.println("Error opening or creating the file");
System.exit(1);
}
catch(IOException ioexception){
System.err.println("General Error with IO");
System.exit(1);
}
while(input.hasNext()){
stringInput = input.nextLine();
try{
fileWriter.append(stringInput + " " + "\n");
}
catch(IOException ioexception){
System.err.println("General Error with IO");
System.exit(1);
}
System.out.printf("Enter your sentence or end of file - ctrl+z or Enter+ctrl+d\n");
}
}//end of constructor
That looks like you are writing the new line chars correctly - maybe the poroblem is with whatever you are using to check the contents of the file?
Ah OK, I see what you mean. I'm on windows at the moment, and notepad displays this
whereas notepad ++ displays this (which is what I wanted)
Is there a way to get them to behave in the same fashion? I presume the problem is that "/n" in the sense that some editors "read" it some don't. Is that the case? But then again, have I then misinterpreted what the API says
This method returns the rest of the current line, excluding any line separator at the end.
I thought that meant that the "/n" will be effectively be ignored when using nextLine()
?
nextLine reads lines from a file and returns them to you without their terminating \n chars.
That's got nothing to do with writing files.
The new line character or sequence depends on the machine where it's running. In reality that will be either or both of decimal 10 (line feed) and 13 (carriage return). (This dates back to typewriters and teletype printers where feeding the pape up one line and returning the print head to the start position were two quite separate things.) Windows preferrs CR and LF. Java's \n is a LF.
Different OSs and different editors vary in how tolerant they are of any variations from their preferred norm. In this case notepad++ is giving handling this file properly and notepad is doing its own thing. So your code is OK; just use notepad++ to check your file contents.
The best solution is to wrap your FileWriter in a BufferedWriter (you should do this anyway for efficiecy reasons) then use BufferedWriter's newLine()
method to write a system-dependent new line char opr sequnce as apropriate.
OK thanks for the explanation :-). I'll build the GUI now (good luck to me!)
Actually my previus description was a bit garbled, and I've now fixed it. Please re-read it. Thanks
Ok, had a look. So I can't really
wrap your FileWriter in a BufferedWriter
like fileWriter = new BufferedWriter(new FileWriter(file,true));
as fileWriter is of FileWriter type, so, can I change the type of fileWriter to be BufferedWriter and then write something like that
...
BufferedWriter fileWriter;
try{
fileWriter = new BufferedWriter(new FileWriter(file,true));
}
catch(SecurityException securityException){//if you don't have write access
System.err.println("You don't have write access to this file");
System.exit(1);
}
catch(FileNotFoundException fileNotFoundException){
System.err.println("Error opening or creating the file");
System.exit(1);
}
catch(IOException ioexception){
System.err.println("General Error with IO");
System.exit(1);
}
then use BufferedWriter's newLine() method to write a system-dependent new line char opr sequnce as apropriate.
Reading the API for newLine() got me thinking: about about creating a string variable and doing something like this:
String separator = System.getProperty("line.separator");
...
try{
fileWriter.append(stringInput + " " + separator);
}
Would that work?
Yes to both.
You can use the system property as you suggest. That's probably what newLine() does anyway. Personally I think newLine() is that little bit clearer when you read the code, and for me that's an important consideration.
Brilliant, changes made and it works like a treat! Now even notepad is showing one sentence per line.
Coding the GUI now. WIll post back. Here is the code so far:
/*SentenceRecorder.java
takes a sentence or word as input and saves it on text file. Every new word/sentence is appended at the end of the file
*/
import java.io.File;
import java.util.Scanner;
import java.io.FileWriter;
import java.lang.SecurityException;//if no permission to write to file
import java.io.FileNotFoundException;//if the file can't be created
import java.io.IOException;
import java.util.Properties;//to get working directory
import java.io.BufferedWriter;
public class SentenceRecorder{
private Scanner input;
private String stringInput;
private String filePath;
private File file;
private BufferedWriter fileWriter;
private String workingDir;
private String separator;
//private Properties workingDir;
/* private String string1;
private String string2; */
public SentenceRecorder(){
String separator = System.getProperty("line.separator");//getting the system-dependent separator
workingDir = System.getProperty("user.dir");
//System.out.println("workingDir is " + workingDir);
input = new Scanner(System.in);
filePath = workingDir + "\\sample.txt";
//filePath = "G:\JAVA\GUI\2015\createFrames\files";
file = new File(filePath);
System.out.printf("Enter your sentence or end of file - ctrl+z or Enter+ctrl+d\n");
try{
fileWriter = new BufferedWriter( new FileWriter(file,true));
}
catch(SecurityException securityException){//if you don't have write access
System.err.println("You don't have write access to this file");
System.exit(1);
}
catch(FileNotFoundException fileNotFoundException){
System.err.println("Error opening or creating the file");
System.exit(1);
}
catch(IOException ioexception){
System.err.println("General Error with IO");
System.exit(1);
}
while(input.hasNext()){
stringInput = input.nextLine();
try{
fileWriter.append(stringInput + separator);
}
catch(IOException ioexception){
System.err.println("General Error with IO");
System.exit(1);
}
System.out.printf("Enter your sentence or end of file - ctrl+z or Enter+ctrl+d\n");
}
}//end of constructor
public void CloseFile(){
try{
fileWriter.close();
}
catch(IOException ioexception){
System.err.println("General Error with IO");
System.exit(1);
}
}//closeFile
}//end of SentenceRecorder
That looks good now!
But please put a printStackTrace() in your exception handlers (especially lines 53 2nd 64) otherwize all you will know is "general error" whereas the stacktrace will tell you exactly what caused the error so you will know how to fix it.
OK added them in, sorry when you mentioned it the first time I thought you said that only because I was having a problem with my code, not in general.
No, especially when writing new code always start off with printStackTrace() everywhere. You never know when the next bug is going reveal itself, and when it does you want all the info you can possibly get.
Cool, thanks.
OK, so now I have a bit of a problem with the GUI and the functionality rather than the look and feel.
So, I have a textArea (input
) where you can type your sentence and a String stringInput
in which the sentence gets copied to before being processed (copied to a file) and the problem seems to be with the method hasNext()
in while(stringInput.hasNext()){
(see the whole inner class here):
private class ProcessButtonHandling implements ActionListener{
public void actionPerformed(ActionEvent event){
stringInput = input.getText();//copy text from textArea to string
try{
fileWriter = new BufferedWriter( new FileWriter(file,true));
}
catch(SecurityException securityException){//if you don't have write access
System.err.println("You don't have write access to this file");
System.exit(1);
}
catch(FileNotFoundException fileNotFoundException){
System.err.println("Error opening or creating the file");
System.exit(1);
}
catch(IOException ioexception){
System.err.println("General Error with IO");
System.exit(1);
}
while(stringInput.hasNext()){
try{
fileWriter.append(stringInput + separator);
}
catch(IOException ioexception){
System.err.println("General Error with IO");
ioexception.printStackTrace();
System.exit(1);
}
//System.out.printf("Enter your sentence or end of file - ctrl+z or Enter+ctrl+d\n");
}
}//end of actionPerformed
}//end of inner class
I get an error at compiling time saying:
G:\JAVA\GUI\2015\createFrames\files\gui>javac *.java
SentenceRecorder.java:85: error: cannot find symbol
while(stringInput.hasNext()){
^
symbol: method hasNext()
location: variable stringInput of type String
1 error
G:\JAVA\GUI\2015\createFrames\files\gui>
Now, is that because I removed import java.util.Scanner;
from the import statements or because the variable (stringInput
) I apply the method to is of type String and not Scanner? Trouble is, the data has now changed, in the sense that the sentence to be processed comes from a textArea, that's why I copied input
(the text area) into stringInput
in stringInput = input.getText();
and then attempted to loop through stringInput like this while(stringInput.hasNext()){
. The API isn't too clear when describing when to use hasNext(). In any case, how should I loop through the string then? Just a normal for loop?
Here is the full class just for reference:
/*SentenceRecorder.java
takes a sentence or word as input and saves it on text file. Every new word/sentence is appended at the end of the file
*/
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import static java.awt.GridBagConstraints.*;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Dimension;
import java.io.File;
//import java.util.Scanner;
import java.io.FileWriter;
import java.lang.SecurityException;//if no permission to write to file
import java.io.FileNotFoundException;//if the file can't be created
import java.io.IOException;
import java.util.Properties;//to get working directory
import java.io.BufferedWriter;
public class SentenceRecorder extends JFrame{
private JLabel instructions;
private JButton submit;
private GridBagLayout gbLayout;
private JButton clear;
private JTextArea input;
//private Scanner input;
private String stringInput;
private String filePath;
private File file;
private BufferedWriter fileWriter;
private String workingDir;
private String separator;
//private Properties workingDir;
/* private String string1;
private String string2; */
public SentenceRecorder(){
super("List of sentences to remember");
String separator = System.getProperty("line.separator");//getting the system-dependent separator
workingDir = System.getProperty("user.dir");
instructions = new JLabel("Enter your sentence or end of file - ctrl+z or Enter+ctrl+d.");
input = new JTextArea(10,12);//holds the text input
submit = new JButton("Submit");//submit button
clear = new JButton("Clear");//clear button
stringInput = "";//initialize string to empty
gbLayout = new GridBagLayout();
//System.out.println("workingDir is " + workingDir);
//input = new Scanner(System.in);
filePath = workingDir + "\\sample.txt";
file = new File(filePath);
setLayout(gbLayout);//set layout of jframe
add(instructions, new GridBagConstraints(0,0,2,1,0,0,CENTER,HORIZONTAL, new Insets(10,15,10,15),0,0));
add(new JScrollPane(input), new GridBagConstraints(0,1,2,1,0.5,0.5,CENTER,BOTH, new Insets(10,15,10,15),10,10));
add(submit, new GridBagConstraints(0,2,1,1,1.0,1.0,CENTER,HORIZONTAL,new Insets(10,15,10,15),1,1));
add(clear, new GridBagConstraints(1,2,1,1,1.0,1.0,CENTER,HORIZONTAL,new Insets(10,15,10,15),1,1));
//System.out.printf("Enter your sentence or end of file - ctrl+z or Enter+ctrl+d\n");
ProcessButtonHandling handler1 = new ProcessButtonHandling();
ClearButtonHandling handler2 = new ClearButtonHandling();
submit.addActionListener(handler1);
clear.addActionListener(handler2);
}//end of constructor
//inner class for event handlings
private class ProcessButtonHandling implements ActionListener{
public void actionPerformed(ActionEvent event){
stringInput = input.getText();//copy text from textArea to string
try{
fileWriter = new BufferedWriter( new FileWriter(file,true));
}
catch(SecurityException securityException){//if you don't have write access
System.err.println("You don't have write access to this file");
System.exit(1);
}
catch(FileNotFoundException fileNotFoundException){
System.err.println("Error opening or creating the file");
System.exit(1);
}
catch(IOException ioexception){
System.err.println("General Error with IO");
System.exit(1);
}
while(stringInput.hasNext()){
try{
fileWriter.append(stringInput + separator);
}
catch(IOException ioexception){
System.err.println("General Error with IO");
ioexception.printStackTrace();
System.exit(1);
}
//System.out.printf("Enter your sentence or end of file - ctrl+z or Enter+ctrl+d\n");
}
}//end of actionPerformed
}//end of inner class
private class ClearButtonHandling implements ActionListener{
public void actionPerformed(ActionEvent event){
stringInput = "";
input.setText("");
}//end of actionPerformed
}
public void CloseFile(){
try{
fileWriter.close();
}
catch(IOException ioexception){
System.err.println("General Error with IO");
ioexception.printStackTrace();
System.exit(1);
}
}//closeFile
}//end of SentenceRecorder
because the variable (stringInput) I apply the method to is of type String and not Scanner?
Yes
If you want to use Scanner methods on data that you have in a String, you can create a Scanner object that uses the String as its input. Hint: It's one of the standard constructors for Scanner.
Ah, I see thank you.
OK so I think I've done it correctly, the application compiles but I get a runtime error, nothing to do with the opening file I don't think. Let's look at the amendments first.
I've created a scanner variable scannerInput
that takes a string input like so scannerInput = new Scanner(stringInput);
and then I have the other variables, private JTextArea input;
and private String stringInput;
, here is the inner class:
import java.util.Scanner;
...
public class SentenceRecorder extends JFrame{
...
private Scanner scannerInput;
private JTextArea input;
private String stringInput;
}
private class ProcessButtonHandling implements ActionListener{
public void actionPerformed(ActionEvent event){
stringInput = input.getText();//copy text from textArea to string
scannerInput = new Scanner(stringInput);
try{
fileWriter = new BufferedWriter( new FileWriter(file,true));
}
catch(SecurityException securityException){//if you don't have write access
System.err.println("You don't have write access to this file");
System.exit(1);
}
catch(FileNotFoundException fileNotFoundException){
System.err.println("Error opening or creating the file");
System.exit(1);
}
catch(IOException ioexception){
System.err.println("General Error with IO");
System.exit(1);
}
while(scannerInput.hasNext()){
stringInput = scannerInput.nextLine();
try{
fileWriter.append(stringInput + separator);
}
catch(IOException ioexception){
System.err.println("General Error with IO");
ioexception.printStackTrace();
System.exit(1);
}
//System.out.printf("Enter your sentence or end of file - ctrl+z or Enter+ctrl+d\n");
}
}//end of actionPerformed
}//end of inner class
So that seems sorted, but now (well, I say now but let's not forget that I couldn't compile till now) I get 2 NullPointerExceptions. Now, I know from previous experience that this kind of error means that something hasn't been initialized, or it has been used without being initialized, so I went through all the variables but they all seem fine, except for two: scannerInput and fileWriter are the only two that are not initialized in the constructor but in the first inner class, and I wonder whether that has anything to do with the errors.
G:\JAVA\GUI\2015\createFrames\files\gui>javac *.java
G:\JAVA\GUI\2015\createFrames\files\gui>java SentenceRecorderTest
Exception in thread "main" java.lang.NullPointerException
at SentenceRecorder.CloseFile(SentenceRecorder.java:110)
at SentenceRecorderTest.main(SentenceRecorderTest.java:7)
G:\JAVA\GUI\2015\createFrames\files\gui>
The lines refer to sentenceRecorder.CloseFile();
found in (SentenceRecorder.java) and fileWriter.close();
found in (SentenceRecorderTest.java), it seems it has problems with the file, but I don't quite understand at what level, in the sense that no action has taken place in the application as I didn't evn run it! Here are the two files:
/*SentenceRecorder.java
takes a sentence or word as input and saves it on text file. Every new word/sentence is appended at the end of the file
*/
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import static java.awt.GridBagConstraints.*;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Dimension;
import java.io.File;
import java.util.Scanner;
import java.io.FileWriter;
import java.lang.SecurityException;//if no permission to write to file
import java.io.FileNotFoundException;//if the file can't be created
import java.io.IOException;
import java.util.Properties;//to get working directory
import java.io.BufferedWriter;
public class SentenceRecorder extends JFrame{
private JLabel instructions;
private JButton submit;
private GridBagLayout gbLayout;
private JButton clear;
private JTextArea input;
private String stringInput;
private String filePath;
private File file;
private BufferedWriter fileWriter;
private String workingDir;
private String separator;
private Scanner scannerInput;
//private Properties workingDir;
/* private String string1;
private String string2; */
public SentenceRecorder(){
super("List of sentences to remember");
String separator = System.getProperty("line.separator");//getting the system-dependent separator
workingDir = System.getProperty("user.dir");
instructions = new JLabel("Enter your sentence or end of file - ctrl+z or Enter+ctrl+d.");
input = new JTextArea(10,12);//holds the text input
submit = new JButton("Submit");//submit button
clear = new JButton("Clear");//clear button
stringInput = "";//initialize string to empty
//scannerInput = new Scanner(stringInput);
gbLayout = new GridBagLayout();
//System.out.println("workingDir is " + workingDir);
//input = new Scanner(System.in);
filePath = workingDir + "\\sample.txt";
file = new File(filePath);
setLayout(gbLayout);//set layout of jframe
add(instructions, new GridBagConstraints(0,0,2,1,0,0,CENTER,HORIZONTAL, new Insets(10,15,10,15),0,0));
add(new JScrollPane(input), new GridBagConstraints(0,1,2,1,0.5,0.5,CENTER,BOTH, new Insets(10,15,10,15),10,10));
add(submit, new GridBagConstraints(0,2,1,1,1.0,1.0,CENTER,HORIZONTAL,new Insets(10,15,10,15),1,1));
add(clear, new GridBagConstraints(1,2,1,1,1.0,1.0,CENTER,HORIZONTAL,new Insets(10,15,10,15),1,1));
//System.out.printf("Enter your sentence or end of file - ctrl+z or Enter+ctrl+d\n");
ProcessButtonHandling handler1 = new ProcessButtonHandling();
ClearButtonHandling handler2 = new ClearButtonHandling();
submit.addActionListener(handler1);
clear.addActionListener(handler2);
}//end of constructor
//inner class for event handlings
private class ProcessButtonHandling implements ActionListener{
public void actionPerformed(ActionEvent event){
stringInput = input.getText();//copy text from textArea to string
scannerInput = new Scanner(stringInput);
try{
fileWriter = new BufferedWriter( new FileWriter(file,true));
}
catch(SecurityException securityException){//if you don't have write access
System.err.println("You don't have write access to this file");
System.exit(1);
}
catch(FileNotFoundException fileNotFoundException){
System.err.println("Error opening or creating the file");
System.exit(1);
}
catch(IOException ioexception){
System.err.println("General Error with IO");
System.exit(1);
}
while(scannerInput.hasNext()){
stringInput = scannerInput.nextLine();
try{
fileWriter.append(stringInput + separator);
}
catch(IOException ioexception){
System.err.println("General Error with IO");
ioexception.printStackTrace();
System.exit(1);
}
//System.out.printf("Enter your sentence or end of file - ctrl+z or Enter+ctrl+d\n");
}
}//end of actionPerformed
}//end of inner class
private class ClearButtonHandling implements ActionListener{
public void actionPerformed(ActionEvent event){
stringInput = "";
input.setText("");
}//end of actionPerformed
}
public void CloseFile(){
try{
fileWriter.close();
}
catch(IOException ioexception){
System.err.println("General Error with IO");
ioexception.printStackTrace();
System.exit(1);
}
}//closeFile
}//end of SentenceRecorder
/*SentenceRecorderTest.java*/
import javax.swing.JFrame;
public class SentenceRecorderTest{
public static void main(String[] args){
SentenceRecorder sentenceRecorder = new SentenceRecorder();
sentenceRecorder.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
sentenceRecorder.CloseFile();
sentenceRecorder.pack();
sentenceRecorder.setVisible(true);
}
}
You call closeFile in your main method (line 130) regardless of whether it has been used (initialised) or not.
Well, yes I do it there because the closing file will happen after the object sentenceRecorder comes into existence. Ah wait, you mean that because the event (opening of the file and writing the info on the file) takes place only when you click the button, the method CloseFile()
is trying to close a file straightaway as soon as the object is created and before the file is even opened?
If that's the case, where would you recommend to call CloseFile()
from? How about calling it at the end of each inner class, after method actionPerformed so that everything is done by the time control gets to there?
That would work ok, and help tp ensure that each batch of new output has been written to the files system.
Cool. One thing though: if I want to call method CloseFile(); from within the inner class, how should I call you? I can't call it directly like this:
private class ClearButtonHandling implements ActionListener{
public void actionPerformed(ActionEvent event){
stringInput = "";
input.setText("");
}//end of actionPerformed
CloseFile();
}
public void CloseFile(){
try{
fileWriter.close();
}
catch(IOException ioexception){
System.err.println("General Error with IO");
ioexception.printStackTrace();
System.exit(1);
}
}//closeFile
as CloseFile() sits directly inside the main class but outside of the inner classes. But I don't have any object there?!
An inner class has access to all the variables and methods in its containing class (that's why you make them inner classes!) so there's no problem calling the outer class's methods from the inner class.
Cool, in that case I must be doing something wrong because the compiler doesn't like that:
G:\JAVA\GUI\2015\createFrames\files\gui>javac *.java
SentenceRecorder.java:100: error: invalid method declaration; return type required
CloseFile();
^
SentenceRecorder.java:107: error: invalid method declaration; return type required
CloseFile();
^
2 errors
G:\JAVA\GUI\2015\createFrames\files\gui>
Here are the two inner classes with CloseFile()
;
}//end of constructor
//inner class for event handlings
private class ProcessButtonHandling implements ActionListener{
public void actionPerformed(ActionEvent event){
stringInput = input.getText();//copy text from textArea to string
scannerInput = new Scanner(stringInput);
try{
fileWriter = new BufferedWriter( new FileWriter(file,true));
}
catch(SecurityException securityException){//if you don't have write access
System.err.println("You don't have write access to this file");
System.exit(1);
}
catch(FileNotFoundException fileNotFoundException){
System.err.println("Error opening or creating the file");
System.exit(1);
}
catch(IOException ioexception){
System.err.println("General Error with IO");
System.exit(1);
}
while(scannerInput.hasNext()){
stringInput = scannerInput.nextLine();
try{
fileWriter.append(stringInput + separator);
}
catch(IOException ioexception){
System.err.println("General Error with IO");
ioexception.printStackTrace();
System.exit(1);
}
//System.out.printf("Enter your sentence or end of file - ctrl+z or Enter+ctrl+d\n");
}
}//end of actionPerformed
CloseFile();
}//end of inner class
private class ClearButtonHandling implements ActionListener{
public void actionPerformed(ActionEvent event){
stringInput = "";
input.setText("");
}//end of actionPerformed
CloseFile();
}
public void CloseFile(){
try{
fileWriter.close();
}
catch(IOException ioexception){
System.err.println("General Error with IO");
ioexception.printStackTrace();
System.exit(1);
}
}//closeFile
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.