Reading a text file after updating it iteratively without stopping the program - java

I am reading a text file in my program and do some modifications in the file and then without stopping the program, I iteretively read the file and again and again, and each time I should be able to read the most recent version of the file. however, after first modification in the file, other times I am still getting that version of the file and seems other modifications are not applied.
Here is how I read the file:
public static Map<String, Float> readOwnersBiasFile() throws IOException {
FileInputStream file = new FileInputStream("ownersBias.txt");
Map<String, Float> ownerBiasMap = new HashMap<String, Float>();
//Construct BufferedReader from InputStreamReader
BufferedReader br = new BufferedReader(new InputStreamReader(file));
String line = null;
while ((line = br.readLine()) != null) {
String[] var = line.split("\\^");
ownerBiasMap.put(var[0], Float.valueOf(var[1]));
}
br.close();
return ownerBiasMap;
}
and here is how I store my modifications:
public static void storeOwnersUtilityMap(Map<String, Float> ownersUtilityMap) throws IOException {
FileInputStream fileInputStream = null;
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
List<String> lines = new ArrayList<String>();
try {
fileInputStream = new FileInputStream("ownersBias.txt");
inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8");
bufferedReader = new BufferedReader(inputStreamReader);
String s;
String[] var;
if (bufferedReader.readLine() == null) {
for (Map.Entry<String, Float> entry : ownersUtilityMap.entrySet()) {
lines.add(entry.getKey().concat("^").concat(String.valueOf(entry.getValue())));
}
} else
while ((s = bufferedReader.readLine()) != null) {
var = s.split("\\^");
if (ownersUtilityMap.containsKey(var[0]))
s = var[0].concat("^").concat(String.valueOf(ownersUtilityMap.get(var[0])));
lines.add(s);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(bufferedReader);
IOUtils.closeQuietly(inputStreamReader);
IOUtils.closeQuietly(fileInputStream);
}
fileWriter(lines, "ownersBias.txt");
}
private static void fileWriter(List<String> list, String fileName) throws IOException {
File fout = new File(fileName);
FileOutputStream fos = new FileOutputStream(fout);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos));
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
bw.write(iterator.next());
bw.newLine();
}
bw.close();
}
And in my main method I have a loop that do some stuff along with reading and modification of the text file.
public static void main(String[] args) throws IOException, TasteException {
for(int i=0;i<10;i++){
map= readOwnersBiasFile();
do some stuff;
storeOwnersUtilityMap(map);
}
}

Should not be necessary to close the programs between re-reads, I've written programs that would read the same file and get any external changes. So that part I know works.
Now the top method readOwnersBiasFile() does not seem to close everything explicitly; I see the BufferedReader closed, but not the InputStreamReader or FileInputStream. When leaving the method, the objects have no references and therefore garbage collection should find them, timing could be an issue. I recommend try-with-resources for anything Closeable.
Operating system might cause differences, however, especially if you're both writing and reading from the same JVM. For example, in Windows you can't delete/move/rename an already open file, but *nix you can. What I don't know (partially because I don't know you're runtime platform) is whether the JVM is being tricky with file handles and tries to reuse in such a way that the changes aren't flushed from the write before things are read or whatever.
If might be worthwhile examining properties on your File object, make sure you see size changes or changed last modified dates or whatever that might indicate you're actually picking up the differences.
I also can't tell anything about the order you're calling things (in particular the first two blocks of code), whether you're doing things multithreaded or what. Open/reading/writing in a multithreaded environment might be problematic

Related

A simple Properties exercise #java

I have a simple Properties exercise
1. Read the time of program run from a configuration document ProgramRunCounter.ini
2. Each time the program run, add one more time
3. Modify the information in document
Here is the code:
class ProgramRunCounter {
public static void counter() throws IOException{
Properties prop = new Properties();
File f = new File("ProgramRunCounter.ini");
BufferedReader br;
BufferedWriter bw;
String key = "times";
String value;
int counter;
if (!f.exists()) {
f.createNewFile();
System.out.println("File created");
}
//Problem is here
br = new BufferedReader(new FileReader(f));
prop.load(br);
value = prop.getProperty(key);
bw = new BufferedWriter(new FileWriter(f));
if (value != null) {
counter = Integer.parseInt(value);
System.out.println("This program has run " + counter + " times");
counter++;
value = String.valueOf(counter);
prop.setProperty(key, value);
prop.store(bw, "One more time run!");
} else {
prop.setProperty(key, "1");
prop.store(bw, "First time run!");
}
br.close();
bw.close();
}
}
public class PropertiesDemo {
public static void main(String[] args) {
try {
ProgramRunCounter.counter();
} catch (IOException e) {
throw new RuntimeException(e.toString());
}
}
}
It works well, but problem is if i change the order of the codes like this, it can't work anymore
br = new BufferedReader(new FileReader(f));
bw = new BufferedWriter(new FileWriter(f));
prop.load(br);
value = prop.getProperty(key);
So why?
It doesn't allow insert bw = new BufferedWriter(new FileWriter(f)); between br = new BufferedReader(new FileReader(f)); and prop.load(br);?
What is the principle?
The devil is in the details. First let me just say, that you may want to just use the "new" (not soo new anymore) IO file API (i.e. Files.newBufferedReader / Files.newBufferedWriter(f.toPath()), ...). Not a must, but it makes things easier.
If you look at the javadoc of newBufferedWriter you see the following:
Opens or creates a file for writing, returning a BufferedWriter that may be used to write text to the file in an efficient manner. The options parameter specifies how the the file is created or opened. If no options are present then this method works as if the CREATE, TRUNCATE_EXISTING, and WRITE options are present. In other words, it opens the file for writing, creating the file if it doesn't exist, or initially truncating an existing regular-file to a size of 0 if it exists.
That efficiency is probably the reason why you do not see any content anymore while you are reading the file (here I assume the same efficiency is also applied under the hood, if you just use your own instantation of BufferedWriter with FileWriter which uses a FileOutputStream with append=false. If you follow all the calls you end up in a native method, so unfortunately I can't say for sure).
Now if you use Files.newBufferedWriter and you just alter the OpenOption to say SYNC or something other then TRUNCATE_EXISTING, the reader is able to load the properties again regardless of which initialization comes first, e.g.
br = Files.newBufferedReader(f.toPath());
bw = Files.newBufferedWriter(f.toPath(), StandardOpenOption.SYNC);

buffered reader and file.delete

I'm creating a mini program that deletes Files using the File.delete() method but I'm having a little bit of an issue if I use the buffered Reader to read the .txt file before I delete it, it doesn't delete the file. I did come up with a solution for it: I just close the buffered reader before I delete the file. however this doesn't make sense to me as to why this is happening can anyone explain this.
import java.io.*;
import java.nio.file.Files;
public class Purge {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
String sample;
boolean result = false;
BufferedReader amg = new BufferedReader(new FileReader("C:/Users/Steven/Desktop/me.txt"));
sample = amg.readLine();
amg.close();// closes the buffered reader
System.out.println("Haha I'm stille here: "+sample);
File anesu = new File("C:/Users/Steven/Desktop/me.txt");
if (anesu.exists()){
try{result = anesu.delete();
}catch( Exception x){
System.out.println("Problem Deleting File"+x);
}
catch( Throwable e){
System.out.println("Problem Deleting File Throwable"+e);
}
}else{
System.out.println("No File ");
}
System.out.println("File has been deleted: "+result);
}
}
When a stream object is garbage collected, its finalizer closes the underlying file descriptor. So, the fact that the delete only works when you added the System.gc() call is strong evidence that your code is somehow failing to close some stream for the file. It may well be a different stream object to the one that is opened in the code that you posted.
Note :
Properly written stream handling code uses a finally block to make sure that streams get closed no matter what.
If you does not want to use System.gc(), read your content with FileInputStream
InputStream in = new FileInputStream(new File("C:/temp/test.txt"));
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder out = new StringBuilder();
try {
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
}
System.out.println(out.toString()); //Prints the string content read from input stream
}
catch(Exception ex) {//TODO}
finally {
reader.close();
}
You can delete the file in the finally block.
A downside to this approach is that if an exception is thrown the file will still be deleted.
public Stream<String> readLines(Path archive) {
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
(new FileInputStream(archive.toFile()))));
return bufferedReader.lines();
} catch (IOException e) {
throw new UncheckedIOException(e);
} finally {
try {
Files.delete(archive);
System.out.println("Deleted: " + archive);
} catch (IOException e) {
System.out.println("Unable to delete: " + archive);
}
}
}

Change from using a BufferedReader for a file, to a String

I have a working app that would take a text file, modify it in stages until it was neat and usable.
every stage would take in a file and modify it, then spit out a file that the next one would buffer in.
i am trying to make it cleaner so i want stop pulling in files, except the first one, and pass the output down the app as a string.
Using this code, how would i do that?
this is the second stage.
try {
BufferedReader bufferedReader = new BufferedReader(new FileReader(new File("C:/Stage_Two.txt")));
StringBuffer stringBuffer = new StringBuffer();
String line;
while ((line = bufferedReader.readLine()) != null) {
Pattern pattern = Pattern.compile("ALL|MESSAGE|Time|PAPER_MAIN|GSP");
if (pattern.matcher(line).find()) {
continue;
}
stringBuffer.append(line);
stringBuffer.append("\n");
}
BufferedWriter bwr = new BufferedWriter(new FileWriter(new File("C:/Stage_Three.txt")));
bwr.write(stringBuffer.toString());
bwr.flush();
bwr.close();
// to see in console
//System.out.println(stringBuffer);
} catch (IOException e) {
}
i have looked into InputStream, InputStreamReader, and Reader...but if its one of those i cant seem to make headway.
I'm not sure how a string would clean it up. The benefit of using readers and writers is that you don't need to have everything in memory. The following code will allow for very large files to be processed.
public void transformFile(File in, File out) throws IOException {
/*
* This method allocates the resources needed to perform the operation
* and releases them once the operation is done. This mechanism is know
* as a try-with-resource. After the try statement exits, the resources
* are closed
*/
try (BufferedReader bin = new BufferedReader(new FileReader(in));
Writer bout = new FileWriter(out)) {
transformBufferedReader(bin, bout);
}
}
private void transformBufferedReader(BufferedReader in, Writer out) throws IOException {
/*
* This method iterates over the lines in the reader and figures out if
* it should be written to the file
*/
String line = null;
while ((line = in.readLine()) != null) {
if (isWriteLine(line)) writeLine(line, out);
}
}
private boolean isWriteLine(String line) throws IOException {
/*
* This tests if the line should be written
*/
return !line.matches("ALL|MESSAGE|Time|PAPER_MAIN|GSP");
}
private void writeLine(String line, Writer writer) throws IOException {
/*
* Write a line out to the writer
*/
writer.append(line);
writer.append('\n');
}
If you insist on using string, you could add the following method.
public String transformString(String str) {
try (BufferedReader bin = new BufferedReader(new StringReader(str));
Writer bout = new StringWriter()) {
transformBufferedReader(bin, bout);
return bout.toString();
} catch (IOException e) {
throw new IllegalStateException("the string readers shouln't be throwing IOExceptions");
}
}

How to read a certain line with a BufferedWriter

I am working on a simple save system for my game, which involves three methods, init load and save.
This is my first time trying out reading and writing to/from a file, so I am not sure if I am doing this correctly, therefore I request assistance.
I want to do this:
When the game starts, init is called. If the file saves does not exist, it is created, if it does, load is called.
Later on in the game, save will be called, and variables will be written to the file, line by line (I am using two in this example.)
However, I am stuck on the load function. I have no idea what do past the point I am on. Which is why I am asking, if it is possible to select a certain line from a file, and change the variable to that specific line.
Here is my code, like I said, I have no idea if I am doing this correctly, so help is appreciated.
private File saves = new File("saves.txt");
private void init(){
PrintWriter pw = null;
if(!saves.exists()){
try {
pw = new PrintWriter(new File("saves.txt"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}else{
try {
load();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void save(){
PrintWriter pw = null;
try {
pw = new PrintWriter(new FileOutputStream(new File("saves.txt"), true));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
pw.println(player.coinBank);
pw.println(player.ammo);
pw.close();
}
public void load() throws IOException{
BufferedReader br = new BufferedReader(new FileReader(saves));
String line;
while ((line = br.readLine()) != null) {
}
}
I was thinking of maybe having an array, parsing the string from the text file into a integer, putting it into the array, and then have the variables equal the values from the array.
Seems like your file is a key=value structure, I suggest you'll use Properties object in java.
Here's a good example.
Your file will look like this:
player.coinBank=123
player.ammo=456
To save:
Properties prop = new Properties();
prop.setProperty("player.coinBank", player.getCoinBank());
prop.setProperty("player.ammo", player.getAmmo());
//save properties to project root folder
prop.store(new FileOutputStream("player.properties"), null);
Then you'll load it like this:
Properties prop = new Properties();
prop.load(new FileInputStream("player.properties"));
//get the property value and print it out
System.out.println(prop.getProperty("player.coinBank"));
System.out.println(prop.getProperty("player.ammo"));
Reading and writing are pretty much symmetric.
You're writing player.coinBank as the first line of the file, and player.ammo as the second line. So, when reading, you should read the first line and assign it to player.coinBank, then read the second line and assign it to player.ammo:
public void load() throws IOException{
try (BufferedReader br = new BufferedReader(new FileReader(saves))) {
player.coinBank = br.readLine();
player.ammo = br.readLine();
}
}
Note the use of the try-with-resources statement here, which makes sure the reader is closed, whatever happens in the method. You should also use this construct when writing to the file.

Reading multiple text file in Java

I have few text files. Each text file contains some path and/or the reference of some other file.
File1
#file#>D:/FilePath/File2.txt
Mod1>/home/admin1/mod1
Mod2>/home/admin1/mod2
File2
Mod3>/home/admin1/mod3
Mod4>/home/admin1/mod4
All I want is, copy all the paths Mod1, Mod2, Mod3, Mod4 in another text file by supplying only File1.txt as input to my java program.
What I have done till now?
public void readTextFile(String fileName){
try {
br = new BufferedReader(new FileReader(new File(fileName)));
String line = br.readLine();
while(line!=null){
if(line.startsWith("#file#>")){
String string[] = line.split(">");
readTextFile(string[1]);
}
else if(line.contains(">")){
String string[] = line.split(">");
svnLinks.put(string[0], string[1]);
}
line=br.readLine();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Currently my code reads the contents of File2.txt only, control does not come back to File1.txt.
Please ask if more inputs are required.
First of all you are jumping to another file without closing the current reader and when you come back you lose the cursor. Read one file first and then write all its contents that match to another file. Close the current reader (Don't close the writer) and then open the next file to read and so on.
Seems pretty simple. You need to write your file once your svnLinks Map is populated, assuming your present code works (haven't seen anything too weird in it).
So, once the Map is populated, you could use something along the lines of:
File newFile = new File("myPath/myNewFile.txt");
// TODO check file can be written
// TODO check file exists or create
FileOutputStream fos = null;
OutputStreamWriter osw = null;
BufferedWriter bw = null;
try {
fos = new FileOutputStream(newFile);
osw = new OutputStreamWriter(fos);
bw = new BufferedWriter(osw);
for (String key: svnLinks.keySet()) {
bw.write(key.concat(" my separator ").concat(svnLinks.get(key)).concat("myNewLine"));
}
}
catch (Throwable t) {
// TODO handle more gracefully
t.printStackTrace();
if (bw != null) {
try {
bw.close();
}
catch (Throwable t) {
t.printStackTrace();
}
}
Here is an non-recursive implementation of your method :
public static void readTextFile(String fileName) throws IOException {
LinkedList<String> list = new LinkedList<String>();
list.add(fileName);
while (!list.isEmpty()) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(new File(list.pop())));
String line;
while ((line = br.readLine()) != null) {
if (line.startsWith("#file#>")) {
String string[] = line.split(">");
list.add(string[1]);
} else if (line.contains(">")) {
String string[] = line.split(">");
svnLinks.put(string[0], string[1]);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
br.close();
}
}
}
Just used a LinkedList to maintain the order. I suggest you to add some counter if you to limit the reading of files to a certain number(depth). eg:
while (!list.isEmpty() && readCount < 10 )
This will eliminate the chance of running the code to infinity(in case of circular reference).

Categories