I'm trying to scan a line of text from a .txt file, split it up into seven numbers, change two of the numbers, and then write the new numbers back into the .txt file. The code below works fine the first time, but seems to have issues with reading from the text file a second time for the new starting String. I've done very similar things multiple times and had no issues, so I'm really not sure why I'm having problems this time around. The code I currently have is:
public void addWin(int numGuesses) throws IOException {
FileWriter writer = new FileWriter(*filepath*);
Scanner scan = new Scanner(new File(*filepath*));
String temp = "0;0;0;0;0;0;0;";
if (scan.hasNextLine()) {
temp = scan.nextLine();
}
String[] statsArr = temp.split(";");
scan.close();
statsArr[0] = Integer.toString(Integer.parseInt(statsArr[0]) + 1);
statsArr[numGuesses] = Integer.toString(Integer.parseInt(statsArr[numGuesses]) + 1);
for (int i = 0; i < statsArr.length; i++) {
writer.append(statsArr[i] + ";");
}
writer.close();
}
Some extra context if needed, this is essentially for a Wordle clone sort of thing for a Discord bot I have. numGuesses is the number of guesses it took to get the word correct. The String being written in and being read is 7 numbers divided up by a semicolon, the first number is the current win streak, the second number is number of times you've won in 1 guess, and so on. The testing I've done seems to place the error somewhere before the scanner closes. A first run through will correctly write the numbers, so if the word was guessed in 3 attempts the file will contain "1;0;0;1;0;0;0;", but the next time the method is called it essentially starts from scratch. Checking the temp variable just after the if statement on a second run through just shows "0;0;0;0;0;0;0;". Sorry for the long-windedness, just trying to provide all possibly helpful details. Thank you in advance!
-
Consider the JavaDoc which states "Whether or not a file is available or may be created depends upon the underlying platform.". So what is happening here, is that when you use new FileWriter(*filepath*) the file is being locked/created blank, so when you use new Scanner(new File(*filepath*)); and scan.hasNextLine() you get a null/empty value.
The easy solution is to simply move the FileWriter further down in your code, and only open it after the scanner has been closed. Also add an else to your if statement so you know if there is an issue with reading from the scanner:
//Move the below line to be later in the code
//FileWriter writer = new FileWriter(*filepath*);
Scanner scan = new Scanner(new File(*filepath*));
String temp = "0;0;0;0;0;0;0;";
if (scan.hasNextLine()) {
temp = scan.nextLine();
}
//Add some debugging
else{
System.out.println("ERROR no data could be read");
}
String[] statsArr = temp.split(";");
scan.close();
statsArr[0] = Integer.toString(Integer.parseInt(statsArr[0]) + 1);
statsArr[numGuesses] = Integer.toString(Integer.parseInt(statsArr[numGuesses]) + 1);
//Create the flie writer here instead
FileWriter writer = new FileWriter(*filepath*);
for (int i = 0; i < statsArr.length; i++) {
writer.append(statsArr[i] + ";");
}
writer.close();
Now assuming the file exists and can be edited, and where numGuesses = 3, then for the following contents:
1;2;3;4;5;6;7;
The output of running the code is as expected (+1 to the 0 and 3rd index)
2;2;3;5;5;6;7;
The reason you only saw 0;0;0;0;0;0;0; was because the code was failing to read from the scanner, and always using the temp value from this line String temp = "0;0;0;0;0;0;0;";. By adding the else check above we can see when it fails.
FileWriter writer = new FileWriter(*filepath*); clears the contents of the file you are trying to read from. You need to move this line after scan.close();
Related
I am trying to go over a bunch of files, read each of them, and remove all stopwords from a specified list with such words. The result is a disaster - the content of the whole file copied over and over again.
What I tried:
- Saving the file as String and trying to look with regex
- Saving the file as String and going over line by line and comparing tokens to the stopwords that are stored in a LinkedHashSet, I can also store them in a file
- tried to twist the logic below in multiple ways, getting more and more ridiculous output.
- tried looking into text / line with the .contains() method, but no luck
My general logic is as follows:
for every word in the stopwords set:
while(file has more lines):
save current line into String
while (current line has more tokens):
assign current token into String
compare token with current stopword:
if(token equals stopword):
write in the output file "" + " "
else: write in the output file the token as is
Tried what's in this question and many other SO questions, but just can't achieve what I need.
Real code below:
private static void removeStopWords(File fileIn) throws IOException {
File stopWordsTXT = new File("stopwords.txt");
System.out.println("[Removing StopWords...] FILE: " + fileIn.getName() + "\n");
// create file reader and go over it to save the stopwords into the Set data structure
BufferedReader readerSW = new BufferedReader(new FileReader(stopWordsTXT));
Set<String> stopWords = new LinkedHashSet<String>();
for (String line; (line = readerSW.readLine()) != null; readerSW.readLine()) {
// trim() eliminates leading and trailing spaces
stopWords.add(line.trim());
}
File outp = new File(fileIn.getPath().substring(0, fileIn.getPath().lastIndexOf('.')) + "_NoStopWords.txt");
FileWriter fOut = new FileWriter(outp);
Scanner readerTxt = new Scanner(new FileInputStream(fileIn), "UTF-8");
while(readerTxt.hasNextLine()) {
String line = readerTxt.nextLine();
System.out.println(line);
Scanner lineReader = new Scanner(line);
for (String curSW : stopWords) {
while(lineReader.hasNext()) {
String token = lineReader.next();
if(token.equals(curSW)) {
System.out.println("---> Removing SW: " + curSW);
fOut.write("" + " ");
} else {
fOut.write(token + " ");
}
}
}
fOut.write("\n");
}
fOut.close();
}
What happens most often is that it looks for the first word from the stopWords set and that's it. The output contains all the other words even if I manage to remove the first one. And the first will be there in the next appended output in the end.
Part of my stopword list
about
above
after
again
against
all
am
and
any
are
as
at
With tokens I mean words, i.e. getting every word from the line and comparing it to the current stopword
After awhile of debugging I believe I have found the solution. This problem is very tricky as you have to use several different scanners and file readers etc. Here is what I did:
I changed how you added to your StopWords set, as it wasn't adding them correctly. I used a buffered reader to read each line, then a scanner to read each word, then added it to the set.
Then when you compared them I got rid of one of your loops as you can easily use the .contains() method to check if the word was a stopWord.
I left you to do the part of writing to the file to take out the stop words, as I'm sure you can figure that out now that everything else is working.
-My sample stop words txt file:
Stop words
Words
-My samples input file was the exact same, so it should catch all three words.
The code:
// create file reader and go over it to save the stopwords into the Set data structure
BufferedReader readerSW = new BufferedReader(new FileReader("stopWords.txt"));
Set<String> stopWords = new LinkedHashSet<String>();
String stopWordsLine = readerSW.readLine();
while (stopWordsLine != null) {
// trim() eliminates leading and trailing spaces
Scanner words = new Scanner(stopWordsLine);
String word = words.next();
while(word != null) {
stopWords.add(word.trim()); //Add the stop words to the set
if(words.hasNext()) {
word = words.next(); //If theres another line, read it
}
else {
break; //else break the inner while loop
}
}
stopWordsLine = readerSW.readLine();
}
BufferedReader outp = new BufferedReader(new FileReader("Words.txt"));
String line = outp.readLine();
while(line != null) {
Scanner lineReader = new Scanner(line);
String line2 = lineReader.next();
while(line2 != null) {
if(stopWords.contains(line2)) {
System.out.println("removing " + line2);
}
if(lineReader.hasNext()) { //If theres another line, read it
line2 = lineReader.next();
}
else {
break; //else break the first while loop
}
}
lineReader.close();
line = outp.readLine();
}
OutPut:
removing Stop
removing words
removing Words
Let me know if I can elaborate any more on my code or why I did something!
The idea behind this is to write to a text file with first name, last and a phone number and save it there. However when restarting the section of the program it will automatically start on a new line. Also facing a problem where for some reason the program keeps looping.
System.out.print("Enter First name: ");
Scanner FN = new Scanner(System.in);
String fn = FN.nextLine();
System.out.print("Enter Last name: ");
Scanner LN = new Scanner(System.in);
String ln = LN.nextLine();
System.out.print("Enter Number: ");
Scanner Num = new Scanner(System.in);
String num = LN.nextLine();
BufferedWriter writer = null;
FileWriter fWriter = new FileWriter("D:\\Second year\\OOP\\Coach1.txt", true);
try {
writer = new BufferedWriter(fWriter);
writer.write(fn + "||");
writer.write(ln + "||");
writer.write(num + "||");
writer.close();
} catch (Exception e) {
System.out.println("Error!");
}
Output:
FirstName|| Last name || number ||
rob || hel ||0774571829 ||
katie || bell || 09275664291 ||
inside try block change the line
writer.write(num + "||");
to
writer.write(num + "|| \n");
You need to make a simple addition at the end of last section printed for each entry. Change:
writer.write(num + "||");
to:
writer.write(num + "||\n");
\n is a new line character, it is used in Strings to indicate that this is a place you want to move to the next line with your String. When next time you try to write to this file, it will start from the new line.
If your intention is to have fixed width of your output Strings (in your example it's fixed, filled with white space characters to make it equal in each column), you need to use System.out.format() instead of System.out.println(). There are a few options how to use it, take a look at this Java tutorial (The format Method section, especially the part about width):
https://docs.oracle.com/javase/tutorial/essential/io/formatting.html
By the way, consider adding finally{} section to your try-catch block and move writer.close() to finally instead of keeping it in try block. It will provide closing writer even if exception occurs before reaching the end of try block.
I am relatively new to programming, especially in Java, so bear that in mind when answering.
I'm programming a simple collectible card game deck building program, but file reading/writing proved to be problematic.
Here is the code for "addDeck" method that I'm trying to get working:
/**
* Adds a deckid and a deckname to decks.dat file.
*/
public static void AddDeck() throws IOException {
// Opens the decks.dat file.
File file = new File("./files/decks.dat");
BufferedReader read = null;
BufferedWriter write = null;
try {
read = new BufferedReader(new FileReader(file));
write = new BufferedWriter(new FileWriter(file));
String line = read.readLine();
String nextLine = read.readLine();
String s = null; // What will be written to the end of the file as a new line.
String newDeck = "Deck ";
int newInd = 00; // Counter index to indicate the new deckid number.
// If there are already existing deckids in the file,
// this will be the biggest existing deckid number + 1.
// If the first line (i.e. the whole file) is initially empty,
// the following line will be created: "01|Deck 01", where the
// number before the '|' sign is deckid, and the rest is the deckname.
if (line == null) {
s = "01" + '|' + newDeck + "01";
write.write(s);
}
// If the first line of the file isn't empty, the following happens:
else {
// A loop to find the last line and the biggest existing deckid of the file.
while (line != null) {
// The following if clause should determine whether or not the next
// line is the last line of the file.
if ((nextLine = read.readLine()) == null) {
// Now the reader should be at the last line of the file.
for (int i = 0; Character.isDigit(line.charAt(i)); i++) {
// Checks the deckid number of the last line and stores it.
s += line.charAt(i);
}
// The value of the last existing deckid +1 will be stored to newInd.
// Also, the divider sign '|' and the new deckname will be added.
// e.g. If the last existing deckid of decks.dat file is "12",
// the new line to be added would read "13|Deck 13".
newInd = (Integer.parseInt(s)) + 1;
s += '|' + newDeck + newInd;
write.newLine();
write.write(s);
}
else {
// If the current line isn't the last line of the file:
line = nextLine;
nextLine = read.readLine();
}
}
}
} finally {
read.close();
write.close();
}
}
The addDeck method should make the decks.dat file longer by one line each time when invoked. But no matter how many times I invoke this method, the
decks.dat has only one line that reads "01|Deck 01".
Also, I need to make a method removeDeck, which removes one whole line from the decks.dat file, and I'm even more at a loss there.
I would be so very grateful for any help!
For starters, this line will create a new file called decks.dat each time the program runs. That is, it will overwrite the contents of the file always.
File file = new File("./files/decks.dat");
As a result, if (line == null) { computes to true always and you end up with "01|Deck 01" in the file always.
To solve this problem, remove the above line and just open the BufferedReader like so:
read = new BufferedReader(new FileReader("./files/decks.dat"));
The second problem is, you cannot really open the same file to read and write at the same time, so you should not open up write like you did. I suggest you collect the updated version into a variable (I suggest StringBuilder) and finally write the contents of this variable into the decks.dat file.
Once you work on these issues, you should be able to make progress with what you intend to do.
I have an application that needs to read only specific content from a text file. I have to read the text from 10,000 different text files arranged in a folder and have to populate the content from all those text files into a single CSV file.
My application runs fine, but it is reading up to file number 999 only. No error, but is not reading file after 999.
Any ideas?
public void calculate(String location) throws IOException{
String mylocation = location;
File rep = new File(mylocation);
File f2 = new File (mylocation + "\\" + "metricvalue.csv");
FileWriter fw = new FileWriter(f2);
BufferedWriter bw = new BufferedWriter (fw);
if(rep.exists() && rep.isDirectory()){
File name[] = rep.listFiles();
for(int j = 0; j < name.length; j++){
if(name[j].isFile()){
String filename = name[j].getPath();
String nameinfo = name[j].getName();
File f1= new File (filename);
FileReader fr = new FileReader(f1);
BufferedReader br = new BufferedReader (fr);
String line = null;
while((line = br.readLine()) != null){
if(line.contains(" | #1 #2 % Correct")){
bw.write(nameinfo + ",");
while((line=br.readLine()) != null) {
if((line.indexOf("#" ) != -1)){
String info[] = line.split("\\s+");
String str = info[2] + "," + info[3] + ",";
bw.write(str);
}
}
}
}
bw.newLine();
br.close();
}
}
}
bw.close();
}
Your platform's file system is limited to 999 open files. You may need to increase the limit or close() the FileReader explicitly:
fr.close();
How to debug:
Put a breakpoint at File name[] = rep.listFiles();
Open variables when Eclipse pauses and check that your array contains all of the file names you want. This will tell you if your problem is there or in your parsing.
You need to debug your code. Here are a couple of pointers to get you started:
File name[] = rep.listFiles();
for(int j =0;j<name.length; j++) {
if(name[j].isFile()) {
What is the size of the array? Figure it out. If there are 10000 elements in the array, that's how many iterations your loop will do, there is simply no other way. Just adding
System.out.println(name.length) will answer this question for you
If the array is shorter than 10000, that's your answer, you simply counted your files incorrectly. If it is not, then your problem must be that one of the "files" isn't really a file (and the test of the if statement fails). Add an else statement to it, and print out the name ... Or better yet, remove this if at all (in general, avoid nested conditionals encompassing the entire body of an outer structure, especially, huge ones like this, it makes your code fragile, and logic very hard to follow), and replace it with
if(!name[j].isFile()) {
System.out.println("Skipping " + name[j] + " because it is not a plain file.");
continue;
}
This will tell you which of 10000 files you are skipping. If it does not print anything, that means, that you do in fact read all 10000 files, as you expect, and the actual problem causing the symptom you are investigating, is elsewhere.
I'm trying to read a file line by line, but every time I run my program I get a NullPointerException at the line spaceIndex = line.indexOf(" "); which obviously means that line is null. HOWEVER. I know for a fact that the file I'm using has exactly 7 lines (even if I print the value of numLines, I get the value 7. And yet I still get a nullpointerexception when I try to read a line into my string.
// File file = some File I take in after clicking a JButton
Charset charset = Charset.forName("US-ASCII");
try (BufferedReader reader = Files.newBufferedReader(file.toPath(), charset)) {
String line = "";
int spaceIndex;
int numLines = 0;
while(reader.readLine()!=null) numLines++;
for(int i = 0; i<numLines; i++) {
line = reader.readLine();
spaceIndex = line.indexOf(" ");
System.out.println(spaceIndex);
}
PS: (I'm not actually using this code to print the index of the space, I replaced the code in my loop since there's a lot of it and it would make it longer to read)
If i'm going about reading the lines the wrong way, it would be great if someone could suggest another way, since so far every way I've tried gives me the same exception. Thanks.
By the time you start your for loop, the reader is already at the end of the file
(from the while loop).
Therefore, readLine() will always return null.
You should get rid of the for loop and do all of your work in the while loop as you first read the file.
You have two options.
First, you could read number of lines from a file this way:
LineNumberReader lnr = new LineNumberReader(new FileReader(new File("File1")));
lnr.skip(Long.MAX_VALUE);
System.out.println(lnr.getLineNumber());
Then read the file right after:
while((line = reader.readLine())!=null)
{
spaceIndex = line.indexOf(" ");
System.out.println(spaceIndex);
}
This first option is an alternative (and in my my opinion, cooler) way of doing this.
Second option (and probably the more sensible) is to do it all at once in the while loop:
while((line = reader.readLine())!=null)
{
numLines++;
spaceIndex = line.indexOf(" ");
System.out.println(spaceIndex);
}