By Shelley


2011-06-25 12:38:27 8 Comments

I'm trying to delete a line of text from a text file without copying to a temporary file. I am trying to do this by using a Printwriter and a Scanner and having them traverse the file at the same time, the writer writing what the Scanner reads and overwriting each line with the same thing, until it gets to the line that I wish to delete. Then, I advance the Scanner but not the writer, and continue as before. Here is the code:

But first, the parameters: My file names are numbers, so this would read 1.txt or 2.txt, etc, and so f specifies the file name. I convert it to a String in the constructor for a file. Int n is the index of the line that I want to delete.

public void deleteLine(int f, int n){
 try{
 Scanner reader = new Scanner(new File(f+".txt")); 
 PrintWriter writer = new PrintWriter(new FileWriter(new File(f+".txt")),false); 
 for(int w=0; w<n; w++)
   writer.write(reader.nextLine()); 
 reader.nextLine(); 
 while(reader.hasNextLine())
   writer.write(reader.nextLine());
 } catch(Exception e){
   System.err.println("Enjoy the stack trace!");
   e.printStackTrace();
 }
}

It gives me strange errors. It says "NoSuchElementException" and "no line found" in the stack trace. It points to different lines; it seems that any of the nextLine() calls can do this. Is it possible to delete a line this way? If so, what am I doing wrong? If not, why? (BTW, just in case you'd want this, the text file is about 500 lines. I don't know if that counts as large or even matters, though.)

3 comments

@aioobe 2011-06-25 13:05:38

As others have pointed out, you might be better off using a temporary file, if there's a slightest risk that your program crashes mid way:

public static void removeNthLine(String f, int toRemove) throws IOException {

    File tmp = File.createTempFile("tmp", "");

    BufferedReader br = new BufferedReader(new FileReader(f));
    BufferedWriter bw = new BufferedWriter(new FileWriter(tmp));

    for (int i = 0; i < toRemove; i++)
        bw.write(String.format("%s%n", br.readLine()));

    br.readLine();

    String l;
    while (null != (l = br.readLine()))
        bw.write(String.format("%s%n", l));

    br.close();
    bw.close();

    File oldFile = new File(f);
    if (oldFile.delete())
        tmp.renameTo(oldFile);

}

(Beware of the sloppy treatment of encodings, new-line characters and exception handling.)


However, I don't like answering questions with "I won't tell you how, because you shouldn't do it anyway.". (In some other situation for instance, you may be working with a file that's larger than half your hard drive!) So here goes:

You need to use a RandomAccessFile instead. Using this class you can both read and write to the file using the same object:

public static void removeNthLine(String f, int toRemove) throws IOException {
    RandomAccessFile raf = new RandomAccessFile(f, "rw");

    // Leave the n first lines unchanged.
    for (int i = 0; i < toRemove; i++)
        raf.readLine();

    // Shift remaining lines upwards.
    long writePos = raf.getFilePointer();
    raf.readLine();
    long readPos = raf.getFilePointer();

    byte[] buf = new byte[1024];
    int n;
    while (-1 != (n = raf.read(buf))) {
        raf.seek(writePos);
        raf.write(buf, 0, n);
        readPos += n;
        writePos += n;
        raf.seek(readPos);
    }

    raf.setLength(writePos);
    raf.close();
}

@Hovercraft Full Of Eels 2011-06-25 13:09:48

@aioobe: but why, what's the advantage, when his/her main rationale for doing it the original way was due to ignorance rather than need? And what if he/she wants to insert text in later that is larger than text deleted?

@aioobe 2011-06-25 13:11:57

The most obvious advantage is that it doesn't require twice the hard-drive space. If the file is really large, it may not be possible to have two copies even temporarily.

@Hovercraft Full Of Eels 2011-06-25 13:13:28

@aioobe: does 500 lines of text qualify as really large? The reason I'm asking is I'm afraid that your answer will mislead someone who is quite new to Java in thinking that this is the best answer for her situation. I believe that it isn't.

@aioobe 2011-06-25 13:13:52

Obviously depends on the lengths of the lines. Doesn't it ;-) Updated the answer anyway.

@Shelley 2011-06-25 13:30:07

@aioobe I appreciate it ;) @Hovercraft Full Of Eels Well, my rationale was the efficiency, but I admit I'm somewhat new to Java. I'm going to do it with the temporary file, the way it should be done. Still... Could you explain a little more fully why doing it the way I was attempting is wrong if it is possible and takes up less space? An explanation would help me greatly in my quest for Java knowledge :-)

@Hovercraft Full Of Eels 2011-06-25 13:35:29

@Shelley: I don't know of any relative speed advantages of one technique over the other, but as aioobe, a RAF has some size advantages while on the other hand there are definite safety advantages of leaving the original file intact until the process is complete, and even then perhaps renaming the original file so it can be saved a a backup before giving the temp file the original name.

@Hovercraft Full Of Eels 2011-06-25 13:35:52

@aioobe: thanks for the edit and agree. Changed -1 vote to +1.

@Jarek Potiuk 2011-06-25 13:02:16

You cannot do it this way. FileWriter can only append to a file, rather than write in the middle of it - You need RandomAccessFile if you want to write in the middle. What you do now - you override the file the first time you write to it (and it gets empty - that's why you get the exception). You can create FileWriter with append flag set to true - but this way you would append to a file rather than write in the middle of it.

I'd really recommend to write to a new file and then rename it at the end.

@Hovercraft Full Of Eels 2011-06-25 13:17:50

Yep, 1+ for recommending to write to a new file and rename it.

@Hovercraft Full Of Eels 2011-06-25 12:54:24

@shelley: you can't do what you are trying to do and what's more, you shouldn't. You should read the file and write to a temporary file for several reasons, for one, it's possible to do it this way (as opposed to what you're trying to do) and for another, if the process gets corrupted, you could bale out without loss of the original file. Now you could update a specific location of a file using a RandomAccessFile, but this is usually done (in my experience) when you are dealing with fixed sized records rather than typical text files.

@Shelley 2011-06-25 13:09:19

That is a good point. Your advice is taken. One more question: to create a temporary file, would I use createTempFile or just the constructor with a different file name? (Sorry if it seems a silly question; I'm a novice with I/O with files.)

@Hovercraft Full Of Eels 2011-06-25 13:15:58

@Shelley: have you gone through the Java tutorials, the I/O section? If not, I advise you to have a look: Basic I/O

Related Questions

Sponsored Content

22 Answered Questions

[SOLVED] How do I save a String to a text file using Java?

59 Answered Questions

[SOLVED] How do I read / convert an InputStream into a String in Java?

33 Answered Questions

[SOLVED] How do I create a Java string from the contents of a file?

21 Answered Questions

[SOLVED] How to read a large text file line by line using Java?

24 Answered Questions

[SOLVED] How to get an enum value from a string value in Java?

  • 2009-03-02 22:56:34
  • Malachi
  • 957413 View
  • 1766 Score
  • 24 Answer
  • Tags:   java enums

25 Answered Questions

[SOLVED] Reading a plain text file in Java

  • 2011-01-17 18:29:13
  • Tim the Enchanter
  • 2188291 View
  • 856 Score
  • 25 Answer
  • Tags:   java file-io ascii

30 Answered Questions

[SOLVED] How to append text to an existing file in Java

18 Answered Questions

[SOLVED] How do I call one constructor from another in Java?

  • 2008-11-12 20:10:19
  • ashokgelal
  • 741162 View
  • 2011 Score
  • 18 Answer
  • Tags:   java constructor

18 Answered Questions

[SOLVED] Why should text files end with a newline?

30 Answered Questions

[SOLVED] How to avoid Java code in JSP files?

  • 2010-07-05 07:24:06
  • former
  • 264166 View
  • 1595 Score
  • 30 Answer
  • Tags:   java jsp scriptlet

Sponsored Content