1 use std::{ 2 fs::{self, File}, 3 io::{self, Read, Seek, Write}, 4 }; 5 6 use super::buffer::EditBuffer; 7 8 use std::path::PathBuf; 9 10 pub const BAK_SUFFIX: &'static str = ".heldbak"; 11 12 pub struct FileManager { 13 name: String, 14 file: File, 15 is_first_open: bool, 16 bak: Option<File>, 17 } 18 19 impl FileManager { 20 pub fn new(file_path: String) -> io::Result<Self> { 21 let ifo_flag = !PathBuf::from(file_path.clone()).exists(); 22 23 let file = File::options() 24 .write(true) 25 .read(true) 26 .create(true) 27 .open(file_path.clone())?; 28 29 Ok(Self { 30 file, 31 is_first_open: ifo_flag, 32 name: file_path, 33 bak: None, 34 }) 35 } 36 37 pub fn init(&mut self, bak: bool) -> io::Result<EditBuffer> { 38 let mut buf = Vec::new(); 39 // 是否备份 40 if bak { 41 self.do_bak(&mut buf)?; 42 } else { 43 self.file.read_to_end(&mut buf)?; 44 } 45 46 Ok(EditBuffer::new(buf)) 47 } 48 49 // 备份 50 fn do_bak(&mut self, buf: &mut Vec<u8>) -> io::Result<()> { 51 let mut bak = File::options() 52 .write(true) 53 .read(true) 54 .create(true) 55 .open(format!("{}{}", self.name, BAK_SUFFIX))?; 56 57 bak.set_len(0)?; 58 59 self.file.read_to_end(buf)?; 60 bak.write_all(&buf)?; 61 62 self.file.seek(io::SeekFrom::Start(0))?; 63 64 if self.bak.is_some() { 65 error!("The backup already exists. The operation may cause data loss."); 66 } 67 68 self.bak = Some(bak); 69 70 Ok(()) 71 } 72 73 pub fn store(&mut self, buf: &EditBuffer) -> io::Result<()> { 74 let data = buf.all_buffer(); 75 76 self.file.set_len(0)?; 77 78 for (idx, line) in data.iter().enumerate() { 79 if idx == data.len() - 1 { 80 self.file.write(&line[..line.len()])?; 81 } else { 82 self.file.write(&line)?; 83 } 84 } 85 86 if self.bak.is_some() { 87 fs::remove_file(format!("{}{}", self.name, BAK_SUFFIX))?; 88 } 89 90 Ok(()) 91 } 92 93 pub fn is_first_open(&mut self) -> bool { 94 self.is_first_open 95 } 96 97 pub fn delete_files(&mut self) -> io::Result<()> { 98 if !self.name.is_empty() { 99 fs::remove_file(self.name.clone())?; 100 } 101 102 if self.bak.is_some() { 103 fs::remove_file(format!("{}{}", self.name, BAK_SUFFIX))?; 104 } 105 Ok(()) 106 } 107 } 108