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);
Related
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
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.
First things first, I am a novice when it comes to Java. I have set myself a little project and I am currently stuck. I am trying to write to a file that already exists, but it just overwrites it. I am trying to replace the line that contains 'maxBooks'.
Here is the code than I am using:
FileWriter writeFile = new FileWriter(fileLocation);
BufferedReader readLines = new BufferedReader(new FileReader(fileLocation));
BufferedWriter writeLines = new BufferedWriter(writeFile);
System.out.println("\n-----File Begin-----");
while((finalLines = readLines.readLine()) != null){
if(finalLines.contains("maxBooks")){
writeLines.newLine();
writeLines.write(finalLines);
System.out.println("This is the if statement");
System.out.println(finalLines);
} else {
fileLines.add(new String(finalLines));
System.out.println("This is the else statement");
System.out.println(finalLines);
}
}
System.out.println("------File End------");
Please bear in mind that I have left out the try and catch. Please let me know how I can edit the text file. Let me know if you need any more info
Thanks :)
EDIT
Sorry, I should clarify. I am just trying to edit 1 line that is in the test file, not the whole text file.
FINAL CODE:
FileWriter writeFile = new FileWriter(fileLocation + ".tmp", true);
BufferedWriter writeLines = new BufferedWriter(writeFile);
BufferedReader readLines = new BufferedReader(new FileReader(fileLocation));
System.out.println("\n-----File Begin-----");
while((finalLines = readLines.readLine()) != null){
if(finalLines.contains("maxBooks")){
writeLines.write("maxBooks = " + maxBooks);
writeLines.newLine();
System.out.println("This is the if statement");
System.out.println(finalLines);
} else {
fileLines.add(new String(finalLines));
System.out.println("This is the else statement");
writeLines.write(finalLines);
writeLines.newLine();
}
}
System.out.println("------File End------");
file2.renameTo(file);
writeLines.close();
You overwrite the file you try to read, which is bad practice. Write to a new file, then rename to the original file.
you read and write on the same fileLocation you're supposed to give two differend locations;
goes something like this
//define newLocation as string that contain path for new file to be written
FileWriter writeFile = new FileWriter(newLocation);
BufferedReader readLines = new BufferedReader(new FileReader(fileLocation));
BufferedWriter writeLines = new BufferedWriter(writeFile);
I created a file named 'test.txt' and then took input from the user to write the input to the file. Everything runs fine. The program doesn't show any error at all. The file is created and the program takes input from the user but when I checked the content of the file, it was empty. Can anyone figure out what is wrong with my code? The code is as follows.
package InputOutput;
import java.io.*;
public class CharacterFileReaderAndFileWriter{
private BufferedReader br = null;
private BufferedWriter bw = null;
private PrintWriter pw = new PrintWriter(System.out, true);
public File createFile() throws IOException{
File f = new File("test.txt");
return f;
}
public void writeToFile() throws IOException{
try{
bw = new BufferedWriter(new FileWriter(createFile()));
}
catch(FileNotFoundException ex){
ex.printStackTrace();
}
//take input from the console (user)
br = new BufferedReader(new InputStreamReader(System.in));
String s;
pw.println("Please enter something");
pw.println("To stop the program, enter 'stop'");
do{
s = br.readLine();
if(s.compareTo("stop")==0)
break;
s+= "\r\n";//adding an new line to the string s
bw.write(s);
}
while(s.compareTo("stop")!=0);
br.close();
bw.close();
}
public static void main(String[] args) throws IOException{
CharacterFileReaderAndFileWriter cfr = new CharacterFileReaderAndFileWriter();
cfr.writeToFile();
}
}
Most example programs show that you have to call.flush() on your BufferedWriter before the .close(). This should not be required, .close() should call .flush() automatically, but it doesn't hurt. Also you should call all the Stream/Writer objects .close() methods in reverse order as well, again correctly written classes should call .close() on all the object they wrap, but it doesn't hurt to do it anyway.
Other things that might catch you out later:
if(s.compareTo("stop")==0)
should be
if ("stop".equalsIgnoreCase(s))
it is more efficient, eliminates the possibility of a NullPointerException on s, handles any case of stop and most importantly more idiomatic Java than using .compareTo()
s+= "\r\n";//adding an new line to the string s
bw.write(s);
should be
bw.write(System.getProperty("line.separator"));
bw.write(s);
The s+= creates intermediate objects and garbage that needs to be collected. Hard coding line endings is bad as well.
You need close the outputstream.
file.close();
i was wondering if there was a way to add to text files already created. because when i do this on an already created file:
public Formatter f = new Formatter("filename.txt");
it re-writes the current filename.txt with a blank one.
thanks, Quinn
Yes, use the constructor with an OutputStream argument instead of a File argument. That way you can open an OutputStream in append mode and do your formatting on that. Link
Try using the constructor for Formatter which takes an Appendable as an argument.
There are several classes which implement the Appendable interface. The most convenient, in your case, should be FileWriter.
This FileWrite constructor will let you open a file (whose name is specified as a String), in append mode.
Use FileOutputStream with append boolean value as true eg new FileOutputStream("C:/concat.txt", true));
Example
public class FileCOncatenation {
static public void main(String arg[]) throws java.io.IOException {
PrintWriter pw = new PrintWriter(new FileOutputStream("C:/concat.txt", true));
File file2 = new File("C:/Text/file2.rxt");
System.out.println("Processing " + file2.getPath() + "... ");
BufferedReader br = new BufferedReader(new FileReader(file2
.getPath()));
String line = br.readLine();
while (line != null) {
pw.println(line);
line = br.readLine();
}
br.close();
// }
pw.close();
System.out.println("All files have been concatenated into concat.txt");
}
}