Read, Edit and Write to File

Updated DavidKroukamp 5 Tallied Votes 22K Views Share

I have seen many people struggling with Reading files and writing files in java, also a great problem is how to edit a file too.

So in this code snippet I have put all these problems into one small program in hopes to help others. So this code snippet will ask for the name of a file, it will then read it in fully, after reading it will ask you to type in the contents of the line you would like to edit, it will then ask you for the replacement text. This will then be edited with new data by replacing the old, the old file will be deleted and then all will be written back to a new file.

Hope its helps people and now hopefully there will be less questions on how to read and write to a file and editing data within a file :) comments on the code are welcome, but before everyone complains that i used the scanner class to read in a file i did provide the other method too, why you may ask? well i wanted a short easy to grasp method to read files.

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.util.Scanner;

public class FileIOTest {

    static StringBuffer stringBufferOfData = new StringBuffer();
    static String filename = null;
    static Scanner sc = new Scanner(System.in);//initiliaze scanner to get user input

    public static void main(String[] args) {

        boolean fileRead = readFile();//call the method to read the file with the files name

        if (fileRead) {//if the read file was successfull
            replacement();//call method to get text to replace, replacement text and output replaced String buffer

            writeToFile();

        }

        System.exit(0);//exit once app is done
    }

    private static boolean readFile() {
        System.out.println("Please enter your files name and path i.e C:\\test.txt: ");//prompt for file name
        filename = sc.nextLine();//read in the file name
        Scanner fileToRead = null;
        try {
            fileToRead = new Scanner(new File(filename)); //point the scanner method to a file

            //check if there is a next line and it is not null and then read it in
            for (String line; fileToRead.hasNextLine() && (line = fileToRead.nextLine()) != null; ) {
                System.out.println(line);//print each line as its read

                stringBufferOfData.append(line).append("\r\n");//this small line here is to appened all text read in from the file to a string buffer which will be used to edit the contents of the file
            }
            fileToRead.close();//this is used to release the scanner from file
            return true;
        } catch (FileNotFoundException ex) {//if the file cannot be found an exception will be thrown
            System.out.println("The file " + filename + " could not be found! " + ex.getMessage());
            return false;

        } finally {//if an error occurs now we close the file to exit gracefully
            fileToRead.close();
            return true;
        }
        /* The below is another way in which to read the file, however i think the shorter method would be the scanner class
        The reason for this is the below commented method uses 5 extra imports:
        import java.io.BufferedReader;
        import java.io.DataInputStream;
        import java.io.FileInputStream;
        import java.io.IOException;
        import java.io.InputStreamReader;
         *//*
        try {
        BufferedReader reader = new BufferedReader(new InputStreamReader(new DataInputStream(new FileInputStream(filename))));
        for (String line; (line = reader.readLine()) != null;) {
        System.out.println(line);
        sb.append(line).append("\r\n");//this small line here is to appened all text read in from the file to a string buffer which will be used to edit the contents of the file
        
        }
        } catch (IOException ex) {
        System.out.println("The file " + filename + " could not be found or opened! "+ex.getMessage());
        System.exit(0);
        }
         */
    }

    private static void writeToFile() {
        try {
            BufferedWriter bufwriter = new BufferedWriter(new FileWriter(filename));
            bufwriter.write(stringBufferOfData.toString());//writes the edited string buffer to the new file
            bufwriter.close();//closes the file

        } catch (Exception e) {//if an exception occurs
            System.out.println("Error occured while attempting to write to file: " + e.getMessage());
        }
    }

    private static void replacement() {
        System.out.println("Please enter the contents of a line you would like to edit: ");//prompt for a line in file to edit
        String lineToEdit = sc.nextLine();//read the line to edit

        System.out.println("Please enter the the replacement text: ");//prompt for a line in file to replace
        String replacementText = sc.nextLine();//read the line to replace

        //System.out.println(sb);//used for debugging to check that my stringbuffer has correct contents and spacing

        int startIndex = stringBufferOfData.indexOf(lineToEdit);//now we get the starting point of the text we want to edit
        int endIndex = startIndex + lineToEdit.length();//now we add the staring index of the text with text length to get the end index

        stringBufferOfData.replace(startIndex, endIndex, replacementText);//this is where the actual replacement of the text happens

        System.out.println("Here is the new edited text:\n" + stringBufferOfData); //used to debug and check the string was replaced


    }
}
peter_budo 2,532 Code tags enforcer Team Colleague Featured Poster

You could have moved that system messages also into methods with which they are associated and code would be little more readable :)

~s.o.s~ 2,560 Failure as a human Team Colleague Featured Poster

Few points:

  1. close() calls should always go in the "finally" blocks
  2. Never use System.exit() to duck out in case of failure. If your code is used in a large/big setting, exitting the JVM in case something fails isn't pleasant. Boolean returns are your friend.
  3. Always check the return status of "delete()" call because file deletion failures are pretty common.
DavidKroukamp 105 Master Poster Team Colleague Featured Poster

Thank you all for the input... to those using the code, now you know how to perfect it :).
i would do it but i cant edit the snippet.

Philippe.Lahaie 42 Posting Whiz in Training
/* The below is another way in which to read the file, however i think the shorter method would be the scanner class
        The reason for this is the below commented method uses 5 extra imports:
        import java.io.BufferedReader;
        import java.io.DataInputStream;
        import java.io.FileInputStream;
        import java.io.IOException;
        import java.io.InputStreamReader;
         */

or you could just import :

import java.io.*;
DavidKroukamp 105 Master Poster Team Colleague Featured Poster

or you could just import :

import java.io.*;

it just increases the size of your code because then you are importing everything from the IO package.

~s.o.s~ 2,560 Failure as a human Team Colleague Featured Poster

it just increases the size of your code because then you are importing everything from the IO package

This statement is a bit misleading. It doesn't increase the size of your code. If you'll disassemble the class file, you'll notice that classes are anyways referenced using their fully qualified names (i.e. java.io.BufferedReader instead of simply BufferedReader). The imports are anyways used to manage/locate compile time dependencies.

That being said, the reason wildcard imports are not recommended (unless throwing together snippets) is that it becomes difficult to trace which class was imported from what package. This of course if mitigated by using an IDE but is a good thing to know just in case.

peter_budo commented: There you go again, "smart pants" answer. Nice summary :) +16
DavidKroukamp 105 Master Poster Team Colleague Featured Poster

This statement is a bit misleading. It doesn't increase the size of your code. If you'll disassemble the class file, you'll notice that classes are anyways referenced using their fully qualified names (i.e. java.io.BufferedReader instead of simply BufferedReader). The imports are anyways used to manage compile time dependencies.

That being said, the reason wildcard imports are not recommended (unless throwing together snippets) is that it becomes difficult to trace which class was imported from what package. This of course if mitigated by using an IDE but is a good thing to know just in case.

Hmmm okay i see maybe i was wrong :P but i find the scanner method so much quicker and simpler to read files... but thank you now i do know that.... maybe my misconception came from back in the day when i was a REAL nOOb now im a semi nOOb lol

stultuske 1,116 Posting Maven Featured Poster

a semi nOOb? if you work hard enough, you can be an expert nOOb in no time ;)

something you could also have changed in your code, to make it a bit more reusable:

public static ArrayList<String> readFile(String fileName) throws IOException{
ArrayList<String> fileContents = new ArrayList<String>();
... // read file and store lines in the ArrayList
return fileContents;
}

and a bit the same for writing the file.

DavidKroukamp 105 Master Poster Team Colleague Featured Poster

a semi nOOb? if you work hard enough, you can be an expert nOOb in no time ;)

something you could also have changed in your code, to make it a bit more reusable:

public static ArrayList<String> readFile(String fileName) throws IOException{
ArrayList<String> fileContents = new ArrayList<String>();
... // read file and store lines in the ArrayList
return fileContents;
}

and a bit the same for writing the file.

Lol :)... and yes i could have used an array list but the main reason was it would have changed the whole method i used to find and replace certain text. maybe not by much but it still would have been very different then my string buffer method. And also i cannot see any advantage of an array list over a normal array(in this circumstance) other then some of the capabilities like remove() but it can also be done in an array.. but has to be in a for statement to find the data to remove... but maybe thats because i havent taken the time to get to know it;)

stultuske 1,116 Posting Maven Featured Poster

main advantage is: when you start reading, how are you supposed to know how many lines are in the file? the ArrayList will automatically increase it's size when your predefined (or default) sized list is full (probably not the best way to explain it, but hey :) ) while you can't enter a sixth element in an array which is instantiated to have only five elements.

DavidKroukamp 105 Master Poster Team Colleague Featured Poster

main advantage is: when you start reading, how are you supposed to know how many lines are in the file? the ArrayList will automatically increase it's size when your predefined (or default) sized list is full (probably not the best way to explain it, but hey :) ) while you can't enter a sixth element in an array which is instantiated to have only five elements.

Hmm yes in that way i can see it as very useful, but at the same time you could just have a integer that's not declared to anything and then once the size is known initiate the integer with appropriate size. The trick is to only initialized the array once you have initialized the integer ;). But yes you are right its much easier... but hey i cant go down without a few words hehehe

stultuske 1,116 Posting Maven Featured Poster

Hmm yes in that way i can see it as very useful, but at the same time you could just have a integer that's not declared to anything and then once the size is known initiate the integer with appropriate size. The trick is to only initialized the array once you have initialized the integer ;). But yes you are right its much easier... but hey i cant go down without a few words hehehe

down side would be that you have to read the file twice ... once to find out how many lines of text are in your file, and once after you've initialized the array to fill it with the contents :)

DavidKroukamp 105 Master Poster Team Colleague Featured Poster

down side would be that you have to read the file twice ... once to find out how many lines of text are in your file, and once after you've initialized the array to fill it with the contents :)

Lol smart....:D

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.