1use chrono::{DateTime, Local};
3use std::fs::{self, File, DirEntry};
4use std::io::{self, BufRead, BufReader, Read, Write};
5use std::vec::IntoIter;
6use std::path::{Path, PathBuf};
7
8pub struct FileUtil;
10
11impl FileUtil {
12 pub fn list(path: &Path, recurse: bool) -> Vec<String> {
20 let mut result = Vec::new();
21 let entries = match fs::read_dir(path) {
22 Ok(entries) => entries,
23 Err(_) => return result,
24 };
25
26 for entry in entries {
27 let entry = match entry {
28 Ok(entry) => entry,
29 Err(_) => continue,
30 };
31 let path = entry.path();
32 if path.is_dir() {
33 if recurse {
34 result.extend(Self::list(&path, true));
35 }
36 result.push(path.to_string_lossy().to_string());
37 } else {
38 result.push(path.to_string_lossy().to_string());
39 }
40 }
41 result
42 }
43
44 pub fn metadata(file_path: &str) -> io::Result<std::fs::Metadata> {
60 fs::metadata(file_path)
61 }
62
63 pub fn last_midified(file_path: &str) -> io::Result<String> {
76 let metadata = fs::metadata(file_path)?;
78 let last_modified = metadata.modified().unwrap();
80 let last_modified: DateTime<Local> = last_modified.into();
82 Ok(last_modified.format("%Y-%m-%d %H:%M:%S").to_string())
84 }
85
86 pub fn read_string(path: &Path) -> Result<String, io::Error> {
93 let mut file = File::open(path)?;
94 let mut contents = String::new();
95 file.read_to_string(&mut contents)?;
96 Ok(contents)
97 }
98
99 pub fn read_string_by_iter(file_path: &str) -> Result<impl Iterator, io::Error> {
100 let file = File::open(file_path)?;
101 let reader = BufReader::new(file);
102 let xx = reader.lines();
103 Ok(xx)
104 }
105
106 pub fn read_bytes(path: &Path) -> Result<Vec<u8>, io::Error> {
113 let mut file = File::open(path)?;
114 let mut contents = Vec::new();
115 file.read_to_end(&mut contents)?;
116 Ok(contents)
117 }
118
119 pub fn write_string(path: &Path, content: String) -> io::Result<()> {
127 let mut file = File::create(path)?;
128 file.write_all(content.as_bytes())?;
129 Ok(())
130 }
131
132 pub fn append_string(path: &Path, content: String) -> io::Result<()> {
140 let mut file = File::options().append(true).open(path)?;
141 file.write_all(content.as_bytes())?;
142 Ok(())
143 }
144
145 pub fn write_bytes(path: &Path, bytes: &[u8]) -> io::Result<()> {
153 let mut file = File::create(path)?;
154 file.write_all(bytes)?;
155 Ok(())
156 }
157
158 pub fn create_dir_with_parents(dir_path: &str) -> io::Result<()> {
160 fs::create_dir_all(dir_path)
161 }
162
163 pub fn delete_file(file_path: &str) -> io::Result<()> {
165 fs::remove_file(file_path)
166 }
167
168 pub fn delete_directory(dir_path: &str) -> io::Result<()> {
170 fs::remove_dir_all(dir_path)
171 }
172
173 pub fn glob(pattern: &str) -> io::Result<Vec<String>> {
188 let mut results = Vec::new();
189 let r = glob::glob(pattern);
190 if r.is_err() {
191 return Err(io::Error::new(io::ErrorKind::Other, r.err().unwrap().to_string()));
192 }
193 for entry in r.unwrap() {
195 match entry {
196 Ok(path) => {
197 let tmp = path.into_os_string().into_string().unwrap();
198 let tmp = tmp.replace("\\", "/");
199 results.push(tmp);
200 },
201 Err(e) => println!("{:?}", e),
202 }
203 }
204 Ok(results)
205 }
206
207 pub fn recursive_files(path: &str) -> Result<Vec<String>, Box<dyn std::error::Error>> {
222 let file_iterator = RecursiveFileIterator::new(Path::new(path))?;
224
225 let results: Vec<String> = file_iterator.map(|item| {
227 let t = item.as_os_str().to_os_string().into_string().unwrap();
228 t.replace("\\", "/")
229 }).collect();
230
231 Ok(results)
232 }
233}
234
235struct RecursiveFileIterator {
237 current_dir_iter: Option<IntoIter<DirEntry>>,
239 subdirs: Vec<PathBuf>,
241}
242
243impl RecursiveFileIterator {
244 pub fn new(root: &Path) -> Result<Self, std::io::Error> {
245 if !root.exists() || !root.is_dir() {
247 return Err(std::io::Error::new(std::io::ErrorKind::NotFound, "目录不存在或不是目录"))
248 }
249
250 let entries: Vec<DirEntry> = std::fs::read_dir(root)?
252 .collect::<Result<Vec<DirEntry>, std::io::Error>>()?;
253
254 Ok(Self {
255 current_dir_iter: Some(entries.into_iter()),
256 subdirs: Vec::new(),
257 })
258 }
259}
260
261impl Iterator for RecursiveFileIterator {
263 type Item = PathBuf;
264
265 fn next(&mut self) -> Option<Self::Item> {
266 loop {
267 if let Some(iter) = &mut self.current_dir_iter {
269 if let Some(entry) = iter.next() {
270 let path = entry.path();
271 if path.is_dir() {
272 self.subdirs.push(path);
273 } else {
274 return Some(path);
275 }
276 } else {
277 self.current_dir_iter = None;
279 }
280 } else {
281 if let Some(subdir) = self.subdirs.pop() {
283 match std::fs::read_dir(&subdir) {
284 Ok(entries) => {
285 let entries:Vec<DirEntry> = entries.filter_map(|e| e.ok()).collect();
287 self.current_dir_iter = Some(entries.into_iter());
288 },
289 Err(e) => {
290 eprintln!("无法读取目录:{:?}: {}", subdir, e);
291 }
292 }
293 } else {
294 return None;
296 }
297 }
298 }
299 }
300}
301
302#[cfg(test)]
303mod tests {
304 use super::*;
305 static ROOT_DIR: &str = "d:/tmp/";
306
307 #[test]
308 fn test_glob() {
309 let xx = FileUtil::glob("D:/*/sub_dir").unwrap();
310 println!("{:?}", xx);
311 }
312
313 #[test]
314 fn test_list() {
315 let temp_dir = Path::new(ROOT_DIR);
316 let sub_dir = temp_dir.join("sub_dir");
317 std::fs::create_dir(&sub_dir).expect("Failed to create sub dir");
318 let file_path = sub_dir.join("test_file.txt");
319 std::fs::File::create(&file_path).expect("Failed to create file");
320
321 let result = FileUtil::list(temp_dir, true);
322 assert!(result.contains(&file_path.to_string_lossy().to_string()));
323 }
324
325 #[test]
326 fn test_read_string() -> io::Result<()> {
327 let temp_path = Path::new(ROOT_DIR).join("temp_file.txt");
328 println!("{:?}", temp_path);
329 let mut temp_file = File::options()
330 .write(true)
331 .create(true)
332 .open(temp_path.as_path())?;
333 let content = "test content".to_string();
334 temp_file
335 .write_all(content.as_bytes())
336 .expect("Failed to write to temp file");
337
338 let result = FileUtil::read_string(temp_path.as_path());
339 assert!(result.is_ok());
340 assert_eq!(result.unwrap(), content);
341 Ok(())
342 }
343
344 #[test]
345 fn test_read_bytes() {
346 let temp_path = Path::new(ROOT_DIR).join("temp_file.txt");
347 let mut temp_file = File::options()
348 .write(true)
349 .open(temp_path.as_path())
350 .unwrap();
351 let content = [1, 2, 3];
352 temp_file
353 .write_all(&content)
354 .expect("Failed to write to temp file");
355
356 let result = FileUtil::read_bytes(temp_path.as_path());
357 assert!(result.is_ok());
358 }
359
360 #[test]
361 fn test_write_string() {
362 let temp_path = Path::new(ROOT_DIR).join("temp_file.txt");
363 let _temp_file = File::options().write(true).open(&temp_path).unwrap();
364 let content = "test write content".to_string();
365
366 let result = FileUtil::write_string(&temp_path, content.clone());
367 assert!(result.is_ok());
368
369 let read_result = FileUtil::read_string(&temp_path);
370 assert!(read_result.is_ok());
371 assert_eq!(read_result.unwrap(), content);
372 }
373
374 #[test]
375 fn test_append_string() {
376 let temp_path = Path::new(ROOT_DIR).join("temp_file.txt");
377 let _temp_file = File::open(&temp_path).unwrap();
378 let initial_content = "initial content".to_string();
379 let append_content = " appended content".to_string();
380 FileUtil::write_string(&temp_path, initial_content.clone())
381 .expect("Failed to write initial content");
382
383 let append_result = FileUtil::append_string(&temp_path, append_content.clone());
384 assert!(append_result.is_ok());
385
386 let read_result = FileUtil::read_string(&temp_path);
387 assert!(read_result.is_ok());
388 assert_eq!(read_result.unwrap(), initial_content + &append_content);
389 }
390
391 #[test]
392 fn test_write_bytes() {
393 let temp_path = Path::new(ROOT_DIR).join("temp_file.txt");
394 let _temp_file = File::open(&temp_path).unwrap();
395 let content = [4, 5, 6];
396
397 let result = FileUtil::write_bytes(&temp_path, &content);
398 assert!(result.is_ok());
399
400 let read_result = FileUtil::read_bytes(&temp_path);
401 assert!(read_result.is_ok());
402 assert_eq!(read_result.unwrap(), content);
403 }
404
405 #[test]
406 fn test_write_bytes_and_read_bytes_with_invalid_path() {
407
408 let results = FileUtil::recursive_files(r"D:\tmp\originalTifData\2025-02-24").unwrap();
409 for r in results {
410 println!("{}", r);
411 }
412 }
413}