Reliable saving JTextArea string in multi entry text file - java

I have a software that stores its data in multible nested data objects. On saving this project data, every instance gets an out handle (BufferedWriter) and writes its own data. Most data is single line and no problem, but there are a few multiline strings that come from JTextAreas. For storing them, I wrote a sub method multiLineWriter(), that splits the string in single lines, writes the number of lines and then the single lines. In theory. Because its not always working. Often it writes out the line count as 1 but then writes out two lines. Or it writes out 1, but writes out two lines with text and an empty line. Its not reliable. After loading the project back, often the complete data is destroyed. A typcal object saving block looks like this:
// *** write data to file
public void writeDataFile(BufferedWriter out) {
try {
out.write(""+getHeadline() );
out.newLine();
out.write(""+getStartDateAsString() );
out.newLine();
out.write(""+getEndDateAsString() );
out.newLine();
out.write(""+getPlaceIndex() );
out.newLine();
multiLineWriter(out, getDescription() );
} catch(Exception e) {}
}
// *** read data from File
public void readDataFile(BufferedReader in) {
try {
setHeadline(in.readLine());
setStartDateAsString(in.readLine());
setEndDateAsString(in.readLine());
setPlaceIndex(in.readLine());
setDescription(multiLineReader(in));
} catch(Exception e) {}
}
The multline writer/reader looks like this:
public void multiLineWriter(BufferedWriter out, String areaText) {
try {
String ls = System.getProperty("line.separator");
String[] lines = areaText.split(ls);
int lineCount = lines.length;
out.write(""+lineCount);
out.newLine();
for(int i = 0;i<lineCount;i++) {
out.write(lines[i]);
out.newLine();
}
} catch(Exception e) {}
}
public String multiLineReader(BufferedReader in) {
String targetString = "";
try {
String ls = System.getProperty("line.separator");
int lineCount = Integer.parseInt(in.readLine());
for(int i = 0;i<lineCount;i++) {
targetString = targetString + in.readLine() + ls;
}
} catch(Exception e) {}
return targetString;
}
As said, lineCount often is 1, but the loop seems to go two or more times because I have sometimes two or three lines after the 1 in a datafile.
This is not reliable for the project. Do you have an idea how I can change the multiLineWriter/reader to reliably store and read the data? The JTextArea save method does not work in this combined data file format.
__More info: __
Properties are a good style for the whole datafile. Since I was allright with the old style seen above most of the times I am sticking to that. Changing the current project to properties is a lot of handwork.
I reuse the out. I have Project Object, that creates the out. This out is then passed to multiple objects with subobjects, sometimes in loops, and everyone writes it data to this single out. After all data is written the project Object of course flushes and closes the stream. The empty exceptions are no problem in this case, because there are no exceptions (so there is nothing to analyse in a stack trace). Its not an exception problem but a logical problem.
The JTextArea read/write is not a good option. At time of saving the file, the data is not in a JTextArea but in a string, that was saved sometime ago during runtime from a JTextArea. To use the write method of JtextArea I would need to restore the string to the area and then use the write method. Because of hundreds of those description objects I would need to do this hundred of times in a save process. Sounds not well. On the other hand I am sure that the read method would not work, because it would read in the datafile up to the end and wouldn't handle the nested datastructure in the datafile.
Its not bad to be human readable. Currently this is helping me, to manually correct the values after a save process, so I am not loosing any data (I now this is stupid, but it works:-)
To be short: I guess I have a problem with the split method of strings and the content of the strings in the string array.
Problem should be made clearer. I have this JTextArea. It is like one field in a display for datasets (its a little private genealogy program that mainly manages hundreds of persons and places). A lot of dataobjects have a description field. Contents of the JTextArea are stored to one single String variable when you change the person in display for example (String personDescription). The writeDataFile() Method you see above is for an event object, that has a description field, too.
So when I write a File, I write from one String to the file. Since this string is taken from the JTextArea, it contains all new line characters that you can produce in a JTextArea. When storing this with one out.write (data) call you have multiple lines in the resulting data file because of possible new line characters in the String. So you can't read all this content back with one in.readLine() call. That's why I created the multiline writers and readers. But they don't work as expected.
Here I show you an exerpt from the resulting datafile
...
# +++ FileCollection:
0
# +++ ImageCollection:
0
58
true
Surname
Arthur
25.09.1877
1
01.01.1950
6
https://familysearch.org/
1
Bekannt ist, dass er auf dem Friedhof Großbeerenstr. lag.
Bekannt ist auch, dass die Trauzeugen bei der Heirat Dorothea Surname und Hermann Surname waren. Hermann ist vermutlich ein Bruder von Valerie.
Weitere Informationen gibt es nicht bisher.
# +++ EventCollection:
0
# +++ FileCollection:
0
...
There is more data before and below, but here is the wrong written data. Its directly below the link to familysearch.org. The first line that follows should have the line count. If there is no text it would have a 0 and the next line would be the info sting '# + EventCollection:'. If there would be one line, it would have a 1 and the next line would be that single line of text for description. Or other numbers depending on the amount of lines from the JTextArea. But as you see, there is written a 1 in this case, but there are 3 (!) Lines of text following.
So the main problem seems to be the way I work with the split method in the multiLineWriter().
String ls = System.getProperty("line.separator");
String[] lines = areaText.split(ls);
int lineCount = lines.length;
This seems to be critical. Since I write the resulting array of the split in a loop, this loop must be done three times? Because I have 3 lines of text in the datafile. But the lineCount is written as a 1? So this seems to be wrong. Could be that this string was not splitted, but still contains line break characters. That would not be what I am looking for. And in the array of splittet Strings there should not be any line break characters anymore (that would destroy the file writing, too).
Hope the problem is better described now. And the question is, how should the multiline writer and reader method be designed to store and read this data reliable.

I tried it myself. As I said there was a problem using the split method on strings. I changed this now to use a Scanner. To be correct, I use some ideas from How do I use System.getProperty("line.separator").toString()?
So in the end I just changed the multiLineWrite Method to use the Scanner (from the util package). It looks like this:
public void multiLineWriter(BufferedWriter out, String areaText) {
List<String> slines = new ArrayList<String>();
try {
Scanner sc = new Scanner(areaText);
while (sc.hasNextLine()) {
slines.add(sc.nextLine());
}
int slineCount = slines.size();
out.write(""+slineCount);
out.newLine();
for(int i = 0;i<slineCount;i++) {
out.write(slines.get(i));
out.newLine();
}
} catch(Exception e) {}
}
So now this seems to be reliable for me. I did a test with parallel writing of the split method and the Scanner method, and the split method had the wrong line count and the Scanner was correct.

Related

I have a problem with writing the content of ArrayLists into a file

So I wrote some code for a vocabulary trainer for my german class and want to write the content of my ArrayLists to a file. However it only writes the first of the 3 ArrayLists into the file when saving. Does anyone know what causes this, or better yet, how to fix it? Thanks for you help!
I have already reset all the ArrayLists and re-implemented the file it should write into, but nothing helped.
These are all just sequences of Code, not the whole program. It is over 400 lines Long so I didnt want to paste the whole thing. The Code runs flawlessly until I open the file I wrote into.
static ArrayList<String> vokabel = new ArrayList<String>();
static ArrayList<String> uebersetzung = new ArrayList<String>();
static ArrayList<Integer> kasten = new ArrayList<Integer>();
static void beenden() {
for(int m = 0; m < groesse; m++) {
String str = vokabel.get(m).toString();
textWriter.write(str);
textWriter.write(" ");
}
textWriter.close();
textWriter.println();
for(int n = 0; n < groesse; n++) {
String str = uebersetzung.get(n).toString();
textWriter.write(str);
textWriter.write(" ");
}
textWriter.close();
textWriter.println();
for(int o = 0; o < groesse; o++) {
String str = kasten.get(o).toString();
textWriter.write(str);
textWriter.write(" ");
}
textWriter.close();
textWriter.println();
System.exit(0);
}
I expect it to write the content of all 3 ArrayLists into the file, though it didn't work up until now.
This is what ends up in the file after entering 3 words with their translations and their corresponding case number. Only the words themselves make it into the file:
Hund Nein Hallo
The reason it only writes the first ArrayList into the file is because you're closing the TextWriter immediately after writing it (and when the TextWriter is closed, it doesn't write stuff). Just remove all the
textWriter.close();
lines, and then put just one right before System.exit(0), and it should work properly.
You write all 3 lists one after the other. AND: Inbetween you close the writer! So you are "lucky" not to get an IOException.
I guess you would like the entries of the 3 lists together (vokabel + uebersetzung+ kasten). Therefore I suggest you create a class taking 3 fields with the information. Give this class a sensible toString() and simply write those objects one line at a time.
Ah and btw: Don't ever call System.exit! It makes your program unusable in a larger context and prevents proper cleanup of resources.
Use Flush.when you have text longer than buffer size it will not write.
System.IO.TextWriter writeFile = new StreamWriter("c:\\textwriter.txt");
writeFile.WriteLine("csharp.net-informations.com");
writeFile.Flush();
writeFile.Close();

Java NetBeans: Why does my string array terminate prematurely?

I found the problem. Apparently, there were random spaces in some of the names in the csv file, which was causing breaks at the 257th entry, as well as several others later on. So, I just took out the spaces and everything works fine now. Thanks to all who tried to help.
I have this code that reads from a csv file, puts the values in String array, and prints them for me to see. It runs fine until it reaches the 257th member of the array (each member has 3 values: last name, first name, and birth year). Here is a functioning version of the code:
package testing.csv.files;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
//.csv comma separated values
String fileName = "C:/Users/Owner/Desktop/Data.csv";
File file = new File(fileName); // TODO: read about File Names
try {
Scanner inputStream = new Scanner(file);
inputStream.next(); //Ignore first line of titles
while (inputStream.hasNext()){
String data = inputStream.next(); // gets a whole line
String[] values = data.split(",");
System.out.println(data);
}
inputStream.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Now, when I change the line
System.out.println(data);
To this:
System.out.println(values[2]);
What I expected to happen was for only the birth years (3rd column) to be printed for every person in the array. However, it only prints out until the 257th person's birth year (out of over 18,000), and gives me the following error message:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
at testing.csv.files.Test.main(Test.java:22)
Java Result: 1
BUILD SUCCESSFUL (total time: 0 seconds)
The "java: 22" seems to be referring to the above snippet of code I posted above that I changed. I am not really sure what the problem is. If my syntax is wrong, why did it print at all? The only thing I can think of is that perhaps a string array can only handle 257 different people each with their own 3 values. If that were the case, then I would need some kind of larger version of string to hold all of my data. Has anyone encountered this problem before? Is the problem somewhere in my syntax and loop?
If there are only two things in the values array, then the highest location that you can index into is 1.
For arrays, you can only index into size - 1 spots; that is, if your array was size ten, you could index into a location 9, or more verbose: array[9].
Change your indexing statement to this:
System.out.println(values[1]);
You might want to see the 257th record in the csv file. Would the split method create three tokens for it? If it should result in less than three tokens and you try to print the third token by typing
System.out.println(values[2]);
you will get an ArrayIndexOutOfBoundsException.
Change:
String data = inputStream.next(); // next() can read the input only till the space
to:
String data = inputStream.nextLine(); // nextLine() reads input including space between the words
Also better way is to iterate the array instead acess through index may be particular line in csv not containing the third column.

Displaying Stats with arrays in Java

I am trying to display statistics from a simple text file using arrays in Java. I know what I am supposed to do, but I don't really how how to code it. So can anybody show me a sample code on how to do it.
So let's say the text file is called gameranking.txt, that contains the following information (This is a simple txt file to use as an example):
Game Event, 1st place, second place, third place, fourth place
World of Warcraft, John, Michael, Bill, Chris
Call of Duty, Michael, Chris, John, Bill
League of Legends, John, Chris, Bill, Michael.
My goal is to display stats such as how many first places, second places.. each individual won in a table like the following
Placement First place, second, third, fourth
John 2 0 1 0
Chris 0 2 0 1
etc...
My thought:
First, I would read the gameranking.txt and stores it to "input". Then I can use the while loop to read each line and store each line into a string called "line", afterward, I would use the array method "split" to pull out each string and store them into individual array. Afterward, I would count which placement each individual won and display them into a neat table using printf.
My first problem is I don't know how to create the arrays for this data. Do I first need to read through the file and see how many strings are in each row and column, then create the array table accordingly? Or can I store each string in an array as I read them?
The pseudocode that I have right now is the following.
Count how many rows are there and store it in row
Count how many column are there and store it in column
Create an array
String [] [] gameranking = new String [row] [column]
Next read the text file and store the info into the arrays
using:
while (input.hasNextLine) {
String line = input.nextLine();
while (line.hasNext()) {
Use line.split to pull out each string
first string = event and store it into the array
second string = first place
third string =......
Somewhere in the code, I need to count the placement....
Can somebody please show me how I should go about doing this?
I am not going to write the full program, but I will try to tackle each question and give you a simple suggestion:
Reading the initial file, you can get each line and store it in a string using a BufferedReader (or if you like, use a LineNumberReader)
BufferedReader br = new BufferedReader(new FileReader(file));
String strLine;
while ((strLine = br.readLine()) != null) {
......Do stuff....
}
At that point, in the while loop you will go through the string (since it comma delimited, you can use that to seperate each section). for each substring you can
a) compare it with first, second, third, fourth to get placement.
b) if its not any of those, then it could either be a game name or a user name
You can figure that out by position or nth substring (ie if this is the 5th substring, its likely to be the first game name. since you have 4 players, the next game name will be the 10th substring, etc.). Do note, I ignored "Game event" as that's not part of the pattern. You can use split to do this or a number of other options, rather than try to explain that I will give you a link to a tutorial I found:
http://pages.cs.wisc.edu/~hasti/cs302/examples/Parsing/parseString.html
As for tabulating results, Basically you can get an int array for each player which keeps track of their 1st, 2nd, 3rd, awards etc.
int[] Bob = new int[4]; //where 0 denotes # of 1st awards, etc.
int[] Jane = new int[4]; //where 0 denotes # of 1st awards, etc.
Showing the table is a matter of organizing the data and using a JTable in a GUI:
http://docs.oracle.com/javase/tutorial/uiswing/components/table.html
Alrighty...Here is what I wrote up, I am sure there is a cleaner and faster way, but this should give you an idea:
String[] Contestants = {"Bob","Bill","Chris","John","Michael"};
int[][] contPlace=new int[Contestants.length][4];
String file = "test.txt";
public FileParsing() throws Exception {
Arrays.fill(contPlace[0], 0);
Arrays.fill(contPlace[1], 0);
Arrays.fill(contPlace[2], 0);
Arrays.fill(contPlace[3], 0);
BufferedReader br = new BufferedReader(new FileReader(file));
String strLine;
while((strLine=br.readLine())!=null){
String[] line = strLine.split(",");
System.out.println(line[0]+"/"+line[1]+"/"+line[2]+"/"+line[3]+"/"+line[4]);
if(line[0].equals("Game Event")){
//line[1]==1st place;
//line[2]==2nd place;
//line[3]==3rd place;
}else{//we know we are on a game line, so we can just pick the names
for(int i=0;i<line.length;i++){
for(int j=0;j<Contestants.length;j++){
if(line[i].trim().equals(Contestants[j])){
System.out.println("j="+j+"i="+i+Contestants[j]);
contPlace[j][i-1]++; //i-1 because 1st substring is the game name
}
}
}
}
}
//Now how to get contestants out of the 2d array
System.out.println("Placement First Second Third Fourth");
System.out.println(Contestants[0]+" "+contPlace[0][0]+" "+contPlace[0][1]+" "+contPlace[0][2]+" "+contPlace[0][3]);
System.out.println(Contestants[1]+" "+contPlace[1][0]+" "+contPlace[1][1]+" "+contPlace[1][2]+" "+contPlace[1][3]);
System.out.println(Contestants[2]+" "+contPlace[2][0]+" "+contPlace[2][1]+" "+contPlace[2][2]+" "+contPlace[2][3]);
System.out.println(Contestants[3]+" "+contPlace[3][0]+" "+contPlace[3][1]+" "+contPlace[3][2]+" "+contPlace[3][3]);
System.out.println(Contestants[4]+" "+contPlace[4][0]+" "+contPlace[4][1]+" "+contPlace[4][2]+" "+contPlace[4][3]);
}
If you need to populate the contestants array or keep track of the games, you will have to insert appropriate code. Also note, using this 2-d array method is probably not best if you want to do anything other than display them. You should be able to take my code, add a main, and see it run.
Since it's a text file, use Scanner class.
It can be customized so that you can read the contents line-by-line, word-by-word, or customized delimiter.
The readfromfile method reads a plain text file one line at a time.
public static void readfromfile(String fileName) {
try {
Scanner scanner = new Scanner(new File(fileName));
scanner.useDelimiter(",");
System.out.println(scanner.next()); //instead of printing, take each word and store them in string array
scanner.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
This will get you started.

Writing long string in Java to file

I'm trying to dump a large integer array (10 000 elements) into a text file but am encountering some problems. I've tried two different approaches and neither seems to be working. Below is the function I've written:
private static void writeToFile(String name, int[] a){
try {
FileWriter fw = new FileWriter(name);
BufferedWriter bw = new BufferedWriter(fw);
bw.write("working");
for (int n: a){
bw.write(n + " ");
}
bw.close();
} catch (IOException e) {
System.err.print("Unable to write to file " + name+ ".");
e.printStackTrace();
}
}
The first thing I tried was creating a string in the for loop and then writing the whole string to the file. Neither method works and gives me the same results as follows:
File is created but left blank
Works fine for shorter arrays (~10 elements)
Works fine if the space is a letter eg: bw.write(n + "a")
Any idea what I'm doing wrong? Or is there an even easier way that I'm not seeing?
Thanks,
Civatrix
Can you explain how you're viewing/reading in the file afterwards? Your code is basically fine as far as I can see (bar moving the close() to a finally block), and it really should make no difference whatsoever whether a space or other letter is added. But that might make a difference e.g. to a text editor, I suppose...?
That code will write all the elements of a[] to the file followed by a space, unless it gets an exception. However it won't write any lines. Is that your problem? If so, you need bw.newLine() after each write().

Outputing text to a file?

After running my program I get this beautifully formatted text:
What do I need add to my code in order to get this text outputted to a .txt file exactly as is?
Assuming you're currently writing your output to the screen using something like System.out.Println(...), a comparable way to write text to a file is to use a PrintStream.
You should be able to find many examples of how to do that if you search; here's one.
import java.io.*;
class PrintStreamDemo {
public static void main(String args[]){
FileOutputStream out;
PrintStream ps; // declare a print stream object
try {
// Create a new file output stream
out = new FileOutputStream("myfile.txt");
// Connect print stream to the output stream
ps = new PrintStream(out);
ps.println ("This data is written to a file:");
System.err.println ("Write successfully");
ps.close();
}
catch (Exception e){
System.err.println ("Error in writing to file");
}
}
}
ps. one caution: the "beautifully formatted" part of your text probably relies on the output being displayed in a monospaced font (all characters the same width); if viewed in a non-monospaced font, the columns won't line up. If you're saving it as a plain .txt file, you don't have control over what font someone else will use to display that file when they open it.
Update:
There are a couple of approaches you could take, if you find you've got a program full of System.out.println calls and you want to direct the output to a file instead.
1) The quick & dirty way would be to open a PrintStream to your desired output file, then call System.setOut() to redirect System.out to the specified PrintStream.
2) A perhaps cleaner way would be to rewrite all the calls of System.out.println to use your own output method. That way when you want to change how you're handling output (for example, send it to multiple files, to both the screen and a file, or whatever), you have just one place to change. More work up front, but gives you more flexibility in the end.
You didnt clarify where data come from, but anyway input or db, I would place on a multidimensional array. Then print will be easy.
P.S. Also to keep format I would use tab separated values "/t"
public class Parser {
private void parseData{
int[][] array = new int[3][12];
// print array in rectangular form
for (int r=0; r<array.length; r++) {
for (int c=0; c<array[r].length; c++) {
System.out.print(array[r][c] + "\t");
}
System.out.println("");
}
}
}

Categories