Home > Blockchain >  How to completely remove a line from a file?
How to completely remove a line from a file?

Time:01-12

How do I completely remove a line in Rust? Not just replace it with an empty line.

In Rust, when you delete a line from a file with the following code as an example:

let mut file: File = File::open("file.txt").unwrap();
let mut buf = String::from("");
file.read_to_string(&mut buf).unwrap(); //Read the file to a buffer
let reader = BufReader::new(&file);

for (index, line) in reader.lines().enumerate() { //Loop through all the lines in the file
    if line.as_ref().unwrap().contains("some text") { //If the line contains "some text", execute the block
        buf = buf.replace(line.as_ref().unwrap(), ""); //Replace "some text" with nothing
    }
}
file.write_all(buf.as_bytes()).unwrap(); //Write the buffer back to the file

file.txt:

random text
random text
random text
some text
random text
random text

When you run the code, file.txt turns into this:

random text
random text
random text

random text
random text

Rather than just

random text
random text
random text
random text
random text

Is there any way to completely remove the line rather than just leaving it blank? Like some sort of special character?

CodePudding user response:

This part is bad-news: buf = buf.replace(line.as_ref().unwrap(), ""); This is doing a search through your entire buffer to find the line contents (without '\n') and replace it with "". To make it behave as you expect you need to add back in the newline. You can just about do this by buf.replace(line.as_ref().unwrap() "\n", "") The problem is that lines() treats more than "\n" as a newline, it also splits on "\r\n". If you know you're always using "\n" or "\r\n" as newlines you can work around this - if not you'll need something tricker than lines().

However, there is a trickier issue. For larger files, this may end up scanning through the string and resizing it many times, giving an O(N^2) style behaviour rather than the expected O(N). Also, the entire file needs to be read into memory, which can be bad for very large files.

The simplest solution to the O(N^2) and memory issues is to do your processing line-by-line, and then move your new file into place. It would look something like this.

//Scope to ensure that the files are closed
{
    let mut file: File = File::open("file.txt").unwrap();
    let mut out_file: File = File::open("file.txt.temp").unwrap();

    let reader = BufReader::new(&file);
    let writer = BufWriter::new(&out_file);

    for (index, line) in reader.lines().enumerate() {
       let line = line.as_ref().unwrap();
       if !line.contains("some text") {
           writeln!(writer, "{}", line);
       }
   }
}
fs::rename("file.txt.temp", "file.txt").unwrap();

This still does not handle cross-platform newlines correctly, for that you'd need a smarter lines iterator.

CodePudding user response:

Hmm could try removing the new line char in the previous line

  •  Tags:  
  • Related