Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to remove the first line of a text file in Rust?

Tags:

string

file

rust

I have a ./file.txt that is:

Lorem ipsum
dolor sit
amet

I want the same ./file.txt to be:

dolor sit
amet

I don't care about the file in any other way; I'm not going to be doing any further manipulation on it or anything like that. I only want to strip the first line.


std::fs::write overrides the entire content of a file. I asssume I would need to read the entire file into a String, remove everything from the start of the string until I find a new line (somehow), then override the entire file with that new string. Though maybe it's just me, all of that feels a bit overkill. I do not care for the entire contents of the file.

The reason I'm asking is because I simply do not know how to do this, especially so if there's a better way of going about this whole thing. If there is an obvious simple answer that'd be great.

This question was answered for Rust 1.0, which is rather outdated, to the point where BufReader.lines() no longer exists.

like image 546
Gremious Avatar asked Sep 18 '25 01:09

Gremious


2 Answers

Did more research, this is the closest I ended up getting.

I don't know if this is optimal, and am not entirely certain this preserves the formatting of the file (though I think it does). I think probably also, there's a better way of loading the file. I don't know many things.

But it works?

use std::{fs, fs::File, fs::OpenOptions};
use std::io::{BufReader, BufRead, Write};

fn main() {
    let mut file = OpenOptions::new()
        .read(true)
        .write(true)
        .open("./file.txt")
        .expect("file.txt doesn't exist or so");

    let mut lines = BufReader::new(file).lines().skip(1)
        .map(|x| x.unwrap())
        .collect::<Vec<String>>().join("\n");

    fs::write("./file.txt", lines).expect("Can't write");
}
like image 67
Gremious Avatar answered Sep 20 '25 15:09

Gremious


You have to read everything but the first line and then override the contents of the file. I'd do it like this:

use std::{
    fs::File,
    io::{self, prelude::*},
};

fn remove_first_line(path: &str) -> io::Result<()> {
    let buf = {
        let r = File::open(path)?;
        let mut reader = io::BufReader::new(r);
        reader.read_until(b'\n', &mut Vec::new())?;
        let mut buf = Vec::new();
        reader.read_to_end(&mut buf)?;
        buf
    };
    File::create(path)?.write_all(&buf)?;
    Ok(())
}

I create a BufReader to read the first line, then I return whatever is left in the file and put it in once again.

If you don't want to close and open the file again, you have to change the seek position so you don't append data to the file:

use std::{
    fs::OpenOptions,
    io::{self, prelude::*},
};

fn remove_first_line(path: &str) -> io::Result<()> {
    let file = OpenOptions::new().read(true).write(true).open(path)?;
    let mut reader = io::BufReader::new(file);
    reader.read_until(b'\n', &mut Vec::new())?;
    let mut buf = Vec::new();
    reader.read_to_end(&mut buf)?;
    let mut file = reader.into_inner();
    file.seek(io::SeekFrom::Start(0))?;
    file.write_all(&buf)?;
    Ok(())
}
like image 33
nrabulinski Avatar answered Sep 20 '25 16:09

nrabulinski