Modifying Existing File Content in Java

Modifying existing file content in Java

As proposed in the accepted answer to a similar question:

open a temporary file in writing mode at the same time, and for each line, read it, modify if necessary, then write into the temporary file. At the end, delete the original and rename the temporary file.

Based on your implementation, something similar to:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class ReplaceFileContents {
public static void main(String[] args) {
new ReplaceFileContents().replace();
}

public void replace() {
String oldFileName = "try.dat";
String tmpFileName = "tmp_try.dat";

BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(new FileReader(oldFileName));
bw = new BufferedWriter(new FileWriter(tmpFileName));
String line;
while ((line = br.readLine()) != null) {
if (line.contains("1313131"))
line = line.replace("1313131", ""+System.currentTimeMillis());
bw.write(line+"\n");
}
} catch (Exception e) {
return;
} finally {
try {
if(br != null)
br.close();
} catch (IOException e) {
//
}
try {
if(bw != null)
bw.close();
} catch (IOException e) {
//
}
}
// Once everything is complete, delete old file..
File oldFile = new File(oldFileName);
oldFile.delete();

// And rename tmp file's name to old file name
File newFile = new File(tmpFileName);
newFile.renameTo(oldFile);

}
}

How to update a file content in Java

The following steps could achieve what you are looking for.

  • Instantiate a FileWriter object to create a tmp file.

     FileWriter fw = new FileWriter("tmp");
  • Read line by line from the source file.

  • Modify this line (string object) in memory.

  • Write out this string in the tmp file.

      fw.write(line);
  • Close the file handles.

  • Rename the tmp file to the source file name.

     sourceFile.renameTo(targetFile);

Modify existing line in file - Java

Here is a way to do it, try it. In this example the file is C:/user.txt and i change the value of George by 1234

public class George {
private static List<String> lines;

public static void main (String [] args) throws IOException{
File f = new File("C:/user.txt");
lines = Files.readAllLines(f.toPath(),Charset.defaultCharset());
changeValueOf("Georges", 1234); // the name and the value you want to modify
Files.write(f.toPath(), changeValueOf("George", 1234), Charset.defaultCharset());
}

private static List<String> changeValueOf(String username, int newVal){
List<String> newLines = new ArrayList<String>();
for(String line: lines){
if(line.contains(username)){
String [] vals = line.split(": ");
newLines.add(vals[0]+": "+String.valueOf(newVal));
}else{
newLines.add(line);
}

}
return newLines;
}
}

This is a working solution, but i think there is some other way more efficient.

Modify contents of text file and write to new file in java

The String variable b is overwriten in each iteration of the loop. You want to append to it instead of overwriting (you may also want to add a newline character at the end):

b += (n + ". " + s + System.getProperty("line.separator"));

Better yet, use a StringBuilder to append the output:

StringBuilder b = new StringBuilder();
int n = 0;
while (file.hasNext()) {
s = file.nextLine();
n++;
System.out.println(n + ". " + s);
b.append(n).append(". ").append(s).append(System.getProperty("line.separator"));
}// end while
PrintWriter printer = new PrintWriter(output);
printer.println(b.toString());

Modify content of large file

TL; DR;

Do not read and write the same file concurrently.

The issue

Your code starts reading, and then immediately truncates the file it is reading.

 reader = new BufferedReader(new FileReader(firstFile));
writerFile = new FileWriter("C:/sqlite/db/tables/" + fileName);
writer = new BufferedWriter(writerFile);

The first line opens a read handle to the file.
The second line opens a write handle to the same file.
It is not very clear if you look at the documentation of FileWriter constructor, but when you do not use a constructor that allows you to specify the append parameter, then the value is false by default, meaning, you immediately truncate the file if it already exists.

At this point (line 2) you have just erased the file you were about to read. So you end up with an empty file.

What about using append=true

Well, then the file is not erased when it is created, which is "good". So you program starts reading the first line, and outputs (to the same file) the filtered version.

So each time a line is read, another is appended.

No wonder your program will never reach the end of the file : each time it advances a line, it creates another line to process. Generally speaking, you'll never reach end of file (well of course if the file is a single line to begin with, you might but that's a corner case).

The solution

Write to a temporary file, and IF (and only IF) you succed, then swap the files if you really need too.

An advantage of this solution : if for whatever reason your processe crahses, you'll have the original file untouched and you could retry later, which is usually a good thing. Your process is "repeatable".

A disadvantage : you'll need twice the space at some point. (Although you could compress the temp file and reduce this factor but still).

About out of memory issues

When working with arbitrarily large files, the path you chose (using buffered readers and writers) is the right one, because you only use one line-worth of memory at a time.

Therefore it generally avoids memory usage issues (unless of course, you have a file without line breaks, in which case it makes no difference at all).

Other solutions, involving reading the whole file at once, then performing the search/replace in memory, then writing the contents back do not scale that well, so it's good you avoided this kind of computation.

Not related but important

Check out the try with resources syntax to properly close your resources (reader / writer). Here you forgot to close the reader, and you are not closing the writer appropriately anyway (that is : in a finally clause).

Another thing : I'm pretty sure no java program written by a mere mortal will beat tools like sed or awk that are available on most unix platforms (and some more). Maybe you'd want to check if rolling your own in java is worth what is a shell one-liner.

Modify a .txt file in Java

I haven't done this in Java recently, but writing an entire file into memory seems like a bad idea.

The best idea that I can come up with is open a temporary file in writing mode at the same time, and for each line, read it, modify if necessary, then write into the temporary file. At the end, delete the original and rename the temporary file.

If you have modify permissions on the file system, you probably also have deleting and renaming permissions.

Modify the content of a file using Java

I would start with closing reader, and flushing writer:

public class FileReplace {
List<String> lines = new ArrayList<String>();
String line = null;

public void doIt() {
try {
File f1 = new File("d:/new folder/t1.htm");
FileReader fr = new FileReader(f1);
BufferedReader br = new BufferedReader(fr);
while ((line = br.readLine()) != null) {
if (line.contains("java"))
line = line.replace("java", " ");
lines.add(line);
}
fr.close();
br.close();

FileWriter fw = new FileWriter(f1);
BufferedWriter out = new BufferedWriter(fw);
for(String s : lines)
out.write(s);
out.flush();
out.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}

public static void main(String args[]) {
FileReplace fr = new FileReplace();
fr.doIt();
}
}

Java to edit the existing file

Your code is not writing a line separator after each line. You need to add it specifically

     while ((line = br.readLine()) != null) {       
line=line.replaceAll("(.{4})", "$1\n ");
bw.write(line);
bw.newLine();
}

How to append text to an existing file in Java?

Are you doing this for logging purposes? If so there are several libraries for this. Two of the most popular are Log4j and Logback.

Java 7+

For a one-time task, the Files class makes this easy:

try {
Files.write(Paths.get("myfile.txt"), "the text".getBytes(), StandardOpenOption.APPEND);
}catch (IOException e) {
//exception handling left as an exercise for the reader
}

Careful: The above approach will throw a NoSuchFileException if the file does not already exist. It also does not append a newline automatically (which you often want when appending to a text file). Another approach is to pass both CREATE and APPEND options, which will create the file first if it doesn't already exist:

private void write(final String s) throws IOException {
Files.writeString(
Path.of(System.getProperty("java.io.tmpdir"), "filename.txt"),
s + System.lineSeparator(),
CREATE, APPEND
);
}

However, if you will be writing to the same file many times, the above snippets must open and close the file on the disk many times, which is a slow operation. In this case, a BufferedWriter is faster:

try(FileWriter fw = new FileWriter("myfile.txt", true);
BufferedWriter bw = new BufferedWriter(fw);
PrintWriter out = new PrintWriter(bw))
{
out.println("the text");
//more code
out.println("more text");
//more code
} catch (IOException e) {
//exception handling left as an exercise for the reader
}

Notes:

  • The second parameter to the FileWriter constructor will tell it to append to the file, rather than writing a new file. (If the file does not exist, it will be created.)
  • Using a BufferedWriter is recommended for an expensive writer (such as FileWriter).
  • Using a PrintWriter gives you access to println syntax that you're probably used to from System.out.
  • But the BufferedWriter and PrintWriter wrappers are not strictly necessary.


Older Java

try {
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("myfile.txt", true)));
out.println("the text");
out.close();
} catch (IOException e) {
//exception handling left as an exercise for the reader
}


Exception Handling

If you need robust exception handling for older Java, it gets very verbose:

FileWriter fw = null;
BufferedWriter bw = null;
PrintWriter out = null;
try {
fw = new FileWriter("myfile.txt", true);
bw = new BufferedWriter(fw);
out = new PrintWriter(bw);
out.println("the text");
out.close();
} catch (IOException e) {
//exception handling left as an exercise for the reader
}
finally {
try {
if(out != null)
out.close();
} catch (IOException e) {
//exception handling left as an exercise for the reader
}
try {
if(bw != null)
bw.close();
} catch (IOException e) {
//exception handling left as an exercise for the reader
}
try {
if(fw != null)
fw.close();
} catch (IOException e) {
//exception handling left as an exercise for the reader
}
}


Related Topics



Leave a reply



Submit