1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
use std::fs::{File, OpenOptions};
use std::io::{BufRead, BufReader, Seek};
#[doc(inline)]
use crate::error::PathError;
pub fn append_open(filename: &str) -> std::result::Result<File, PathError> {
OpenOptions::new()
.create(true)
.append(true)
.open(&filename)
.map_err(|e| PathError::FileAccess(filename.to_owned(), e.to_string()))
}
pub fn rw_open(filename: &str) -> std::result::Result<File, PathError> {
OpenOptions::new()
.read(true)
.write(true)
.open(filename)
.map_err(|e| PathError::FileAccess(filename.to_owned(), e.to_string()))
}
pub fn pop_last_line(file: &mut File) -> Option<String> {
let (line, pos) = find_last_line(file)?;
file.set_len(pos).ok()?;
Some(line)
}
pub fn find_last_line(file: &mut File) -> Option<(String, u64)> {
let mut last_pos = 0u64;
let mut last_line = String::new();
if file.metadata().ok()?.len() == 0u64 {
return None;
}
let mut reader = BufReader::new(file);
while let Some((line, pos)) = last_line_and_pos(&mut reader) {
last_pos = pos;
last_line = line.trim_end().to_owned();
}
Some((last_line, last_pos))
}
fn last_line_and_pos<R: BufRead + Seek>(reader: &mut R) -> Option<(String, u64)> {
let pos = reader.stream_position().ok()?;
let mut line = String::new();
if 0 == reader.read_line(&mut line).ok()? {
return None;
}
Some((line, pos))
}