use std::{
fs::File,
io::{self, Read, Write},
path::{Path, PathBuf},
};
use parking_lot::Mutex;
use tracing::warn;
static LOCK: Mutex<()> = Mutex::new(());
pub fn file_to_string(file_name: &str) -> Result<String, io::Error> {
if !PathBuf::from(file_name).exists() {
warn!("file not exist:{}", file_name);
return Ok("".to_string());
}
let file = File::open(file_name)?;
file_to_string_impl(&file)
}
pub fn file_to_string_impl(file: &File) -> Result<String, io::Error> {
let file_length = file.metadata()?.len() as usize;
let mut data = vec![0; file_length];
let result = file.take(file_length as u64).read_exact(&mut data);
match result {
Ok(_) => Ok(String::from_utf8_lossy(&data).to_string()),
Err(_) => Err(io::Error::new(
io::ErrorKind::InvalidData,
"Failed to read file",
)),
}
}
pub fn string_to_file(str_content: &str, file_name: &str) -> io::Result<()> {
let lock = LOCK.lock();
let bak_file = format!("{}.bak", file_name);
if let Ok(prev_content) = file_to_string(file_name) {
string_to_file_not_safe(&prev_content, &bak_file)?;
}
string_to_file_not_safe(str_content, file_name)?;
drop(lock);
Ok(())
}
fn string_to_file_not_safe(str_content: &str, file_name: &str) -> io::Result<()> {
if let Some(parent) = Path::new(file_name).parent() {
std::fs::create_dir_all(parent)?;
}
let file = File::create(file_name)?;
write_string_to_file(&file, str_content, "UTF-8")
}
fn write_string_to_file(file: &File, data: &str, _encoding: &str) -> io::Result<()> {
let mut os = io::BufWriter::new(file);
os.write_all(data.as_bytes())?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_file_to_string() {
let temp_file = tempfile::NamedTempFile::new().unwrap();
let file_path = temp_file.path().to_str().unwrap();
let content = "Hello, World!";
std::fs::write(file_path, content).unwrap();
let result = file_to_string(file_path);
assert!(result.is_ok());
assert_eq!(result.unwrap(), content);
}
#[test]
fn test_string_to_file() {
let temp_file = tempfile::NamedTempFile::new().unwrap();
let file_path = temp_file.path().to_str().unwrap();
let content = "Hello, World!";
let result = string_to_file(content, file_path);
assert!(result.is_ok());
assert_eq!(std::fs::read_to_string(file_path).unwrap(), content);
}
}