use anyhow::Result;
use std::{
collections::HashMap,
fs::{self, read_dir, File, OpenOptions},
hash::Hash,
io::{BufRead, BufReader, Seek, SeekFrom, Write},
path::Path,
str::FromStr,
};
use crate::{strs, times};
pub fn open_file(file_path: &str) -> File {
create_pdir(file_path);
OpenOptions::new()
.read(true) .write(true) .append(true) .create(true) .open(file_path)
.unwrap()
}
pub fn create_pdir(file_path: &str) {
let path = Path::new(file_path);
let prefix = path.parent().unwrap();
if !prefix.exists() {
std::fs::create_dir_all(prefix).unwrap();
}
}
pub fn create_file(file_path: &str) -> Result<File, std::io::Error> {
create_pdir(file_path);
File::create(file_path)
}
pub fn exists(path: &str) -> bool {
Path::new(path).exists()
}
pub fn is_file(path: &str) -> bool {
Path::new(path).is_file()
}
pub fn is_dir(path: &str) -> bool {
Path::new(path).is_dir()
}
pub fn create_dir_all(dir_path: &str) {
if !exists(dir_path) {
std::fs::create_dir_all(dir_path).unwrap();
}
}
pub fn list_dir_name(dir_path: &str) -> Vec<String> {
let mut ret = vec![];
if exists(dir_path) {
for ele in read_dir(dir_path).unwrap() {
let ele = ele.unwrap();
if ele.metadata().unwrap().is_dir() {
ret.push(ele.file_name().to_str().unwrap().to_string())
}
}
}
ret
}
pub fn list_file_name(dir_path: &str) -> Vec<String> {
let mut ret = Vec::new();
if exists(dir_path) {
for ele in read_dir(dir_path).unwrap() {
let ele = ele.unwrap();
if ele.metadata().unwrap().is_file() {
ret.push(ele.file_name().to_str().unwrap().to_string())
}
}
}
ret
}
pub fn list_all_file(dir_path: &str, filter: fn(path: &str) -> bool) -> Vec<String> {
let mut ret = Vec::new();
if exists(dir_path) {
match read_dir(dir_path) {
Ok(entrys) => {
for ele in entrys {
let ele = ele.unwrap();
let metadata = ele.metadata().unwrap();
let path = ele.path().display().to_string();
let path = path.replace("\\", "/");
if metadata.is_dir() {
let mut files = list_all_file(path.as_str(), filter);
ret.append(&mut files);
}
if metadata.is_file() {
if filter(&path) {
ret.push(path)
}
}
}
}
Err(err) => {
eprintln!("{err}")
}
}
}
ret
}
pub fn splite_file_by_lines(path: &str, out_path: &str, splite_lines: i32) -> Vec<String> {
let (_, name, ext) = file_path_attr(path);
let mut new_files = vec![];
match File::open(path) {
Ok(input) => {
let buffered = BufReader::new(input);
let mut lines = 0;
let mut str = String::new();
for line in buffered.lines() {
if let Ok(s) = line {
str.push_str(&s);
str.push_str("\n");
lines += 1;
if lines > 0 && lines % splite_lines == 0 {
let new_file_name =
format!("{out_path}/{name}_{}_{lines}.{ext}", lines - splite_lines);
create_file(&new_file_name)
.unwrap()
.write_all(str.as_bytes())
.unwrap();
str.clear();
new_files.push(new_file_name);
}
}
}
if !str.is_empty() {
let new_file_name =
format!("{out_path}/{name}_{}_{lines}.{ext}", lines - splite_lines);
create_file(&new_file_name)
.unwrap()
.write_all(str.as_bytes())
.unwrap();
new_files.push(new_file_name);
}
}
Err(err) => {
println!("{err}");
}
}
new_files
}
pub fn read_line<T>(path: &str, deal_line: fn(line: String) -> Option<T>) -> Vec<T> {
let mut vec = Vec::new();
match File::open(path) {
Ok(input) => {
let buffered = BufReader::new(input);
for line in buffered.lines() {
if let Ok(s) = line {
let value = deal_line(s);
match value {
Some(v) => {
vec.push(v);
}
None => {}
}
}
}
}
Err(err) => {
println!("{err}");
}
}
vec
}
pub fn read_line_map<K, V, T>(
path: &str,
deal_line: fn(line: String) -> Option<T>,
kvf: fn(t: T) -> (K, V),
) -> HashMap<K, V>
where
K: Eq + Hash,
{
let mut vec: HashMap<K, V> = HashMap::new();
match File::open(path) {
Ok(input) => {
let buffered = BufReader::new(input);
for line in buffered.lines() {
if let Ok(s) = line {
let value = deal_line(s);
match value {
Some(v) => {
let (k, v) = kvf(v);
vec.insert(k, v);
}
None => {}
}
}
}
}
Err(err) => {
println!("{err}");
}
}
vec
}
pub fn file_size(path: &str) -> u64 {
if exists(path) {
let meta = fs::symlink_metadata(path).unwrap();
meta.len()
} else {
0
}
}
pub fn read_last_line(path: &str, buf_size: u64) -> Option<String> {
match File::open(path) {
Ok(mut input) => {
let file_size = file_size(path);
if file_size > buf_size {
let start_idx = file_size - buf_size;
input.seek(SeekFrom::Start(start_idx)).unwrap();
}
let bf = BufReader::new(input);
match bf.lines().last() {
Some(line) => match line {
Ok(l) => {
return Some(l);
}
Err(err) => {
println!("seek 失败 {err}");
None
}
},
None => None,
}
}
Err(_) => {
None
}
}
}
pub fn line_size(path: &str) -> usize {
if let Ok(f) = File::open(path) {
let file_size = file_size(path);
println!("size={file_size}");
if file_size > 0 {
let buffered = BufReader::new(f);
return buffered.lines().count();
}
}
0
}
pub async fn load_async<T>(path: &str, filter: fn(path: &str) -> bool) -> Vec<T>
where
T: FromStr + Default + Send + 'static,
{
let files;
if is_dir(path) {
files = list_all_file(path, filter);
} else {
files = vec![path.to_string()]
}
let mut hds = vec![];
for ele in files {
hds.push(tokio::spawn(async move {
let items: Vec<T> = load_file(&ele);
items
}));
}
let mut all = Vec::new();
for ele in hds {
match ele.await {
Ok(mut items) => {
all.append(&mut items);
}
Err(err) => {
println!("{err}")
}
}
}
all
}
pub fn load<T>(path: &str, filter: fn(path: &str) -> bool) -> Vec<T>
where
T: FromStr + Default,
{
let files;
if is_dir(path) {
files = list_all_file(path, filter);
} else {
files = vec![path.to_string()]
}
let mut all = Vec::new();
for ele in files {
let mut items = load_file(&ele);
all.append(&mut items);
}
all
}
pub fn load_map<K, V, T>(
path: &str,
filter: fn(path: &str) -> bool,
kvf: fn(t: T) -> (K, V),
) -> HashMap<K, V>
where
T: FromStr + Default,
K: std::hash::Hash + std::cmp::Eq,
{
let files;
if is_dir(path) {
files = list_all_file(path, filter);
} else {
files = vec![path.to_string()];
}
let mut t = (HashMap::new(), kvf);
for ele in files {
load_file_by_line(&ele, &mut t, |l, m| match T::from_str(&l) {
Ok(t) => {
let (k, v) = m.1(t);
m.0.insert(k, v);
}
Err(_) => {}
});
}
t.0
}
pub fn load_file<T>(path: &str) -> Vec<T>
where
T: FromStr + Default,
{
read_line(path, |s| match T::from_str(&s) {
Ok(t) => Some(t),
Err(_) => {
println!("line {s} pase err");
None
}
})
}
pub fn load_file_map<T, K, V>(path: &str, kvf: fn(t: T) -> (K, V)) -> HashMap<K, V>
where
T: FromStr + Default,
K: Hash + Eq,
{
read_line_map(
path,
|s| match T::from_str(&s) {
Ok(t) => Some(t),
Err(_) => {
println!("line {s} pase err");
None
}
},
kvf,
)
}
pub fn file_path_attr(file_path: &str) -> (&str, &str, &str) {
let path = Path::new(file_path);
let dir = path.parent().unwrap().to_str().unwrap();
let name = path.file_stem().unwrap().to_str().unwrap();
let ext = path.extension().unwrap().to_str().unwrap();
(dir, name, ext)
}
pub fn load_file_by_line<T>(path: &str, t: &mut T, line_fn: fn(line: String, t: &mut T)) {
match File::open(path) {
Ok(input) => {
let buffered = BufReader::new(input);
for line in buffered.lines() {
if let Ok(line) = line {
line_fn(line, t);
}
}
}
Err(err) => {
println!("{err}");
}
}
}
pub fn load_by_line<T>(
path: &str,
filter: fn(path: &str) -> bool,
t: &mut T,
line_fn: fn(line: String, t: &mut T),
) {
let files;
if is_dir(path) {
files = list_all_file(path, filter);
} else {
files = vec![path.to_string()];
}
for ele in files {
load_file_by_line(&ele, t, line_fn);
}
}
pub fn splite_file_by_date(
file_path: &str,
out_path: &str,
sufix: &str,
filter: fn(&str) -> bool,
spl: &str,
time_idx: usize,
limit_size: usize,
fmt: &str,
) {
let mut f_paths = vec![];
if is_file(file_path) {
f_paths.push(file_path.to_string());
} else {
f_paths = list_all_file(file_path, filter);
}
let mut f_map: HashMap<String, String> = HashMap::new();
for f_path in f_paths {
match File::open(f_path) {
Ok(input) => {
let buffered = BufReader::new(input);
for line in buffered.lines() {
if let Ok(mut line) = line {
let items: Vec<&str> = line.split(spl).collect();
if items.len() < time_idx + 1 {
eprintln!(
"{line} len is {} time_idx:{time_idx} out of index",
items.len()
);
continue;
}
let time_item = items[time_idx];
let date_path = match fmt {
"ts" => {
let t = times::unix_str_2_date_time(time_item);
times::get_date_path(&t)
}
_ => {
let t = times::parse_date_time(time_item);
t.format(times::YMD_PATH).to_string()
}
};
line.push('\n');
if f_map.contains_key(&date_path) {
let content = f_map.get_mut(&date_path).unwrap();
if limit_size > 0 {
if content.len() > limit_size {
write_bytes(
&format!("{out_path}/{date_path}{sufix}"),
content.as_bytes(),
);
content.clear();
}
}
content.push_str(&line);
} else {
f_map.insert(date_path, line);
}
}
}
}
Err(err) => {
println!("{err}");
}
}
}
for (date_path, content) in f_map {
write_bytes(
&format!("{out_path}/{date_path}{sufix}"),
content.as_bytes(),
);
}
}
pub fn block_file(
file_path: &str,
filter: fn(&str) -> bool,
out_path: &str,
sufix: &str,
block_site: usize,
) {
let mut f_paths = vec![];
if is_file(file_path) {
f_paths.push(file_path.to_string());
} else {
f_paths = list_all_file(file_path, filter);
}
let mut str = String::new();
let mut idx = 0;
for f_path in f_paths {
match File::open(f_path) {
Ok(input) => {
let buffered = BufReader::new(input);
for line in buffered.lines() {
if let Ok(line) = line {
if str.len() > block_site {
write_bytes(&format!("{out_path}/{idx:0>4}{sufix}"), str.as_bytes());
str.clear();
idx += 1;
}
str.push_str(&line);
str.push('\n');
}
}
}
Err(err) => {
eprintln!("{err}")
}
}
}
if !str.is_empty() {
write_bytes(&format!("{out_path}/{idx:0>4}{sufix}"), str.as_bytes());
}
}
fn write_bytes(file_path: &str, bytes: &[u8]) {
open_file(file_path).write_all(bytes).unwrap()
}
pub fn splite_file_by_field_idx(
file_path: &str,
out_path: &str,
sufix: &str,
filter: fn(&str) -> bool,
spl: &str,
split_idx: usize,
keep_idxs: &str,
limit_size: usize,
) {
let mut f_paths = vec![];
if is_file(file_path) {
f_paths.push(file_path.to_string());
} else {
f_paths = list_all_file(file_path, filter);
}
let mut f_map: HashMap<String, String> = HashMap::new();
let keep_idxs: Vec<usize> = strs::str_2_vec(keep_idxs, ",");
for f_path in f_paths {
match File::open(f_path) {
Ok(input) => {
let buffered = BufReader::new(input);
for line in buffered.lines() {
if let Ok(line) = line {
let items: Vec<&str> = line.split(spl).collect();
if items.len() < split_idx + 1 {
continue;
}
let item = items[split_idx];
if f_map.contains_key(item) {
let content = f_map.get_mut(item).unwrap();
if limit_size > 0 {
if content.len() > limit_size {
write_bytes(
&format!("{out_path}/{item}{sufix}"),
content.as_bytes(),
);
content.clear();
}
}
if keep_idxs.is_empty() {
content.push_str(&line);
} else {
let mut keep_items = vec![];
for idx in &keep_idxs {
keep_items.push(items[*idx]);
}
content.push_str(&keep_items.join(spl));
}
content.push('\n');
} else {
f_map.insert(item.to_string(), line);
}
}
}
}
Err(err) => {
println!("{err}")
}
}
}
for (k, v) in f_map {
if !v.is_empty() {
write_bytes(&format!("{out_path}/{k}{sufix}"), v.as_bytes());
}
}
}
#[test]
fn test_f() {
let str = "wx1_111";
let c = "_";
let (pre, suf, ..) = match str.find(c) {
Some(idx) => (&str[..idx], &str[idx + c.len()..], true),
None => (str, "", false),
};
println!("{pre},{suf}")
}