37

How do I replace a line of text found within a text file?

I have a string such as:

Do the dishes0

And I want to update it with:

Do the dishes1

(and vise versa)

How do I accomplish this?

ActionListener al = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    JCheckBox checkbox = (JCheckBox) e.getSource();
                    if (checkbox.isSelected()) {
                        System.out.println("Selected");
                        String s = checkbox.getText();
                        replaceSelected(s, "1");
                    } else {
                        System.out.println("Deselected");
                        String s = checkbox.getText();
                        replaceSelected(s, "0");
                    }
                }
            };

public static void replaceSelected(String replaceWith, String type) {

}

By the way, I want to replace ONLY the line that was read. NOT the entire file.

Eveno
  • 373
  • 1
  • 3
  • 5
  • 9
    Read the ENTIRE file. Change the line. Write the ENTIRE file. – nhgrif Nov 18 '13 at 04:22
  • I've tried to do this using RandomAccessFile and BufferedReader and BufferedWriters. I really need some code designed for my specific purpose. I seem to be doing something wrong every time I try. – Eveno Nov 18 '13 at 04:23
  • Then I suggest posting the code where you're making this effort and let SO help you figure out what you're doing wrong. – nhgrif Nov 18 '13 at 04:24
  • It's long gone now. As I've said I've tried many different methods. Storing it in a temporary array.. creating a new file.. none of it worked. – Eveno Nov 18 '13 at 04:25
  • Well you need to go back to implementing these methods, and when you get stuck, come back here and post that. – nhgrif Nov 18 '13 at 04:26
  • Please post your code. Don't expect others to write it for you. If you post an honest attempt, we're all happy to comment on what's right with it, what's wrong with it, and what you need to change to make it work. But if you can't show us your effort, it's unlikely that anyone here will make much of an effort to help you. – Dawood ibn Kareem Nov 18 '13 at 04:34
  • http://pastebin.com/5jwnM0xM Here is my code. Taken from Mikes reply. This updates the value with a 1 and a 0 depending on whether the JCheckBox is checked. However, if there is more than one value it writers both values to the top line. http://www.rune-shadows.com/before.PNG http://www.rune-shadows.com/after.PNG . And as I said if there is one value it changes 1/0 just fine. – Eveno Nov 18 '13 at 14:22

8 Answers8

51

At the bottom, I have a general solution to replace lines in a file. But first, here is the answer to the specific question at hand. Helper function:

public static void replaceSelected(String replaceWith, String type) {
    try {
        // input the file content to the StringBuffer "input"
        BufferedReader file = new BufferedReader(new FileReader("notes.txt"));
        StringBuffer inputBuffer = new StringBuffer();
        String line;

        while ((line = file.readLine()) != null) {
            inputBuffer.append(line);
            inputBuffer.append('\n');
        }
        file.close();
        String inputStr = inputBuffer.toString();

        System.out.println(inputStr); // display the original file for debugging

        // logic to replace lines in the string (could use regex here to be generic)
        if (type.equals("0")) {
            inputStr = inputStr.replace(replaceWith + "1", replaceWith + "0"); 
        } else if (type.equals("1")) {
            inputStr = inputStr.replace(replaceWith + "0", replaceWith + "1");
        }

        // display the new file for debugging
        System.out.println("----------------------------------\n" + inputStr);

        // write the new string with the replaced line OVER the same file
        FileOutputStream fileOut = new FileOutputStream("notes.txt");
        fileOut.write(inputStr.getBytes());
        fileOut.close();

    } catch (Exception e) {
        System.out.println("Problem reading file.");
    }
}

Then call it:

public static void main(String[] args) {
    replaceSelected("Do the dishes", "1");   
}

Original Text File Content:

Do the dishes0
Feed the dog0
Cleaned my room1

Output:

Do the dishes0
Feed the dog0
Cleaned my room1
----------------------------------
Do the dishes1
Feed the dog0
Cleaned my room1

New text file content:

Do the dishes1
Feed the dog0
Cleaned my room1


And as a note, if the text file was:

Do the dishes1
Feed the dog0
Cleaned my room1

and you used the method replaceSelected("Do the dishes", "1");, it would just not change the file.


Since this question is pretty specific, I'll add a more general solution here for future readers (based on the title).

// read file one line at a time
// replace line as you read the file and store updated lines in StringBuffer
// overwrite the file with the new lines
public static void replaceLines() {
    try {
        // input the (modified) file content to the StringBuffer "input"
        BufferedReader file = new BufferedReader(new FileReader("notes.txt"));
        StringBuffer inputBuffer = new StringBuffer();
        String line;

        while ((line = file.readLine()) != null) {
            line = ... // replace the line here
            inputBuffer.append(line);
            inputBuffer.append('\n');
        }
        file.close();

        // write the new string with the replaced line OVER the same file
        FileOutputStream fileOut = new FileOutputStream("notes.txt");
        fileOut.write(inputBuffer.toString().getBytes());
        fileOut.close();

    } catch (Exception e) {
        System.out.println("Problem reading file.");
    }
}
Michael Yaworski
  • 13,410
  • 19
  • 69
  • 97
  • You need to make sure you close your streams when you're finished with them. – Sammy Guergachi Aug 18 '14 at 16:34
  • 1
    @SammyGuergachi You're right. I always get lazy and don't do that. If you suggest an edit, I'll approve it. – Michael Yaworski Aug 18 '14 at 18:12
  • You also should use StringBuilder instead of "while (...) input += line + '\n'" for best practises http://stackoverflow.com/questions/1532461/stringbuilder-vs-string-concatenation-in-tostring-in-java – user2602807 May 15 '15 at 10:35
  • 1
    Consider replacing "String input" with "StringBuilder input" and use it as input.append(line + "\n);". A string is an immutable object while a StringBuilder is not. Therefore every time you modify a String you create a new Object. Once you are done with your data get the string with "input.toString()". – Redauser Mar 31 '17 at 10:49
  • what is type here. I have quite similer situation please have a look . it will help https://stackoverflow.com/questions/50809375/how-to-replace-an-string-after-a-specific-line-in-a-file-using-java – Shubham Jain Jun 12 '18 at 08:48
  • @Redauser The `replace` method is only called on `inputStr` once, so switching to a `StringBuilder` wouldn't decrease the amount of objects being created. – Kröw Jul 05 '18 at 11:28
  • @Kröw he's refering to the `line + "\n"` part, which creates unnecessary String objects – Michael Yaworski Jul 05 '18 at 14:21
  • @MichaelYaworski Oh, I just noticed the edit log. This makes much more sense now. Thanks for clearing that up. – Kröw Jul 05 '18 at 17:05
  • For the answer to the specific question, why would you read in the entire file, change a single char, then print the whole file back out again? That seems awfully wasteful. – Kröw May 16 '19 at 17:17
  • This overwrites the existing file. – mLstudent33 Apr 15 '23 at 10:58
49

Since Java 7 this is very easy and intuitive to do.

List<String> fileContent = new ArrayList<>(Files.readAllLines(FILE_PATH, StandardCharsets.UTF_8));

for (int i = 0; i < fileContent.size(); i++) {
    if (fileContent.get(i).equals("old line")) {
        fileContent.set(i, "new line");
        break;
    }
}

Files.write(FILE_PATH, fileContent, StandardCharsets.UTF_8);

Basically you read the whole file to a List, edit the list and finally write the list back to file.

FILE_PATH represents the Path of the file.

Tuupertunut
  • 741
  • 7
  • 9
  • Suggestion: Also explain how to it is important to write to a temp file, and then move that file into place over the first file in order to make the change atomic. (And welcome to StackOverflow!) – rrauenza Jun 03 '16 at 22:27
  • 1
    @rrauenza That is not necessary and would mostly be an overkill. That being said it certainly wouldn't be hard to implement in few lines. If you want to demonstrate that, why not make your own answer (or suggest an edit)? – Tuupertunut Jun 04 '16 at 18:26
  • I don't know Java well enough and you should get credit for the answer. (As a reviewer, I'm asked to make suggestions to improve "first posts.") – rrauenza Jun 04 '16 at 18:29
  • I need to refer to http://www.java2s.com/Tutorials/Java/java.nio.file/Files/Java_Files_readAllLines_Path_path_Charset_cs_.htm, as above answer was not complete – vikramvi Feb 05 '17 at 11:25
  • 2
    Above answer produced an error : The method write(Path, byte[], OpenOption...) in the type Files is not applicable for the arguments (Path, byte[], Charset) – Max Alexander Hanna Aug 14 '17 at 14:08
  • It shouldn't have `byte[]` as the second argument anyway. It looks like you have the "fileContent" list as `byte[]` instead of `List` or it is invalid in some other way. – Tuupertunut Aug 15 '17 at 17:21
  • This answer is by far the neatest solution – RobOhRob Jul 26 '19 at 17:58
  • in Capture the Flag, I tried this and it said that a tmp file was created so it's wrong. – mLstudent33 Apr 15 '23 at 11:14
3

Sharing the experience with Java Util Stream

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;    

public static void replaceLine(String filePath, String originalLineText, String newLineText) {
            Path path = Paths.get(filePath);
            // Get all the lines
            try (Stream<String> stream = Files.lines(path, StandardCharsets.UTF_8)) {
                // Do the line replace
                List<String> list = stream.map(line -> line.equals(originalLineText) ? newLineText : line)
                        .collect(Collectors.toList());
                // Write the content back
                Files.write(path, list, StandardCharsets.UTF_8);
            } catch (IOException e) {
                LOG.error("IOException for : " + path, e);
                e.printStackTrace();
            }
        }

Usage

replaceLine("test.txt", "Do the dishes0", "Do the dishes1");
Community
  • 1
  • 1
jfk
  • 4,335
  • 34
  • 27
2

If replacement is of different length:

  1. Read file until you find the string you want to replace.
  2. Read into memory the part after text you want to replace, all of it.
  3. Truncate the file at start of the part you want to replace.
  4. Write replacement.
  5. Write rest of the file from step 2.

If replacement is of same length:

  1. Read file until you find the string you want to replace.
  2. Set file position to start of the part you want to replace.
  3. Write replacement, overwriting part of file.

This is the best you can get, with constraints of your question. However, at least the example in question is replacing string of same length, So the second way should work.

Also be aware: Java strings are Unicode text, while text files are bytes with some encoding. If encoding is UTF8, and your text is not Latin1 (or plain 7-bit ASCII), you have to check length of encoded byte array, not length of Java string.

hyde
  • 60,639
  • 21
  • 115
  • 176
2

I was going to answer this question. Then I saw it get marked as a duplicate of this question, after I'd written the code, so I am going to post my solution here.

Keeping in mind that you have to re-write the text file. First I read the entire file, and store it in a string. Then I store each line as a index of a string array, ex line one = array index 0. I then edit the index corresponding to the line that you wish to edit. Once this is done I concatenate all the strings in the array into a single string. Then I write the new string into the file, which writes over the old content. Don't worry about losing your old content as it has been written again with the edit. below is the code I used.

public class App {

public static void main(String[] args) {

    String file = "file.txt";
    String newLineContent = "Hello my name is bob";
    int lineToBeEdited = 3;

    ChangeLineInFile changeFile = new ChangeLineInFile();
    changeFile.changeALineInATextFile(file, newLineContent, lineToBeEdited);



}

}

And the class.

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;

public class ChangeLineInFile {

public void changeALineInATextFile(String fileName, String newLine, int lineNumber) {
        String content = new String();
        String editedContent = new String();
        content = readFile(fileName);
        editedContent = editLineInContent(content, newLine, lineNumber);
        writeToFile(fileName, editedContent);

    }

private static int numberOfLinesInFile(String content) {
    int numberOfLines = 0;
    int index = 0;
    int lastIndex = 0;

    lastIndex = content.length() - 1;

    while (true) {

        if (content.charAt(index) == '\n') {
            numberOfLines++;

        }

        if (index == lastIndex) {
            numberOfLines = numberOfLines + 1;
            break;
        }
        index++;

    }

    return numberOfLines;
}

private static String[] turnFileIntoArrayOfStrings(String content, int lines) {
    String[] array = new String[lines];
    int index = 0;
    int tempInt = 0;
    int startIndext = 0;
    int lastIndex = content.length() - 1;

    while (true) {

        if (content.charAt(index) == '\n') {
            tempInt++;

            String temp2 = new String();
            for (int i = 0; i < index - startIndext; i++) {
                temp2 += content.charAt(startIndext + i);
            }
            startIndext = index;
            array[tempInt - 1] = temp2;

        }

        if (index == lastIndex) {

            tempInt++;

            String temp2 = new String();
            for (int i = 0; i < index - startIndext + 1; i++) {
                temp2 += content.charAt(startIndext + i);
            }
            array[tempInt - 1] = temp2;

            break;
        }
        index++;

    }

    return array;
}

private static String editLineInContent(String content, String newLine, int line) {

    int lineNumber = 0;
    lineNumber = numberOfLinesInFile(content);

    String[] lines = new String[lineNumber];
    lines = turnFileIntoArrayOfStrings(content, lineNumber);

    if (line != 1) {
        lines[line - 1] = "\n" + newLine;
    } else {
        lines[line - 1] = newLine;
    }
    content = new String();

    for (int i = 0; i < lineNumber; i++) {
        content += lines[i];
    }

    return content;
}

private static void writeToFile(String file, String content) {

    try (Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "utf-8"))) {
        writer.write(content);
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

private static String readFile(String filename) {
    String content = null;
    File file = new File(filename);
    FileReader reader = null;
    try {
        reader = new FileReader(file);
        char[] chars = new char[(int) file.length()];
        reader.read(chars);
        content = new String(chars);
        reader.close();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    return content;
}

}
1
        //Read the file data
        BufferedReader file = new BufferedReader(new FileReader(filepath));
        StringBuffer inputBuffer = new StringBuffer();
        String line;

        while ((line = file.readLine()) != null) {
            inputBuffer.append(line);
            inputBuffer.append('\n');
        }
        file.close();
        String inputStr = inputBuffer.toString();


        // logic to replace lines in the string (could use regex here to be generic)

            inputStr = inputStr.replace(str, " ");
        //'str' is the string need to update in this case it is updating with nothing

        // write the new string with the replaced line OVER the same file
        FileOutputStream fileOut = new FileOutputStream(filer);
        fileOut.write(inputStr.getBytes());
        fileOut.close();
0

Well you would need to get a file with JFileChooser and then read through the lines of the file using a scanner and the hasNext() function

http://docs.oracle.com/javase/7/docs/api/javax/swing/JFileChooser.html

once you do that you can save the line into a variable and manipulate the contents.

Corjava
  • 340
  • 2
  • 6
  • 17
  • I'll look into this. Thanks. Would you mind posting a quick example of what it would like though all together so I have an idea? – Eveno Nov 18 '13 at 04:29
  • You can find everything you need in the [Java Tutorial](http://docs.oracle.com/javase/tutorial/essential/io/). – MarsAtomic Nov 18 '13 at 04:44
0

just how to replace strings :) as i do first arg will be filename second target string third one the string to be replaced instead of targe

public class ReplaceString{
      public static void main(String[] args)throws Exception {
        if(args.length<3)System.exit(0);
        String targetStr = args[1];
        String altStr = args[2];
        java.io.File file = new java.io.File(args[0]);
        java.util.Scanner scanner = new java.util.Scanner(file);
        StringBuilder buffer = new StringBuilder();
        while(scanner.hasNext()){
          buffer.append(scanner.nextLine().replaceAll(targetStr, altStr));
          if(scanner.hasNext())buffer.append("\n");
        }
        scanner.close();
        java.io.PrintWriter printer = new java.io.PrintWriter(file);
        printer.print(buffer);
        printer.close();
      }
    }
amar
  • 24
  • 2