1use chrono::{DateTime, Local};
3use std::fs::{self, File};
4use std::io::{self, Read, Write};
5use std::path::Path;
6
7pub struct FileUtil;
9
10impl FileUtil {
11 pub fn list(path: &Path, recurse: bool) -> Vec<String> {
19 let mut result = Vec::new();
20 let entries = match fs::read_dir(path) {
21 Ok(entries) => entries,
22 Err(_) => return result,
23 };
24
25 for entry in entries {
26 let entry = match entry {
27 Ok(entry) => entry,
28 Err(_) => continue,
29 };
30 let path = entry.path();
31 if path.is_dir() {
32 if recurse {
33 result.extend(Self::list(&path, true));
34 }
35 result.push(path.to_string_lossy().to_string());
36 } else {
37 result.push(path.to_string_lossy().to_string());
38 }
39 }
40 result
41 }
42
43 pub fn metadata(file_path: &str) -> io::Result<std::fs::Metadata> {
59 fs::metadata(file_path)
60 }
61
62 pub fn last_midified(file_path: &str) -> io::Result<String> {
75 let metadata = fs::metadata(file_path)?;
77 let last_modified = metadata.modified().unwrap();
79 let last_modified: DateTime<Local> = last_modified.into();
81 Ok(last_modified.format("%Y-%m-%d %H:%M:%S").to_string())
83 }
84
85 pub fn read_string(path: &Path) -> Result<String, io::Error> {
92 let mut file = File::open(path)?;
93 let mut contents = String::new();
94 file.read_to_string(&mut contents)?;
95 Ok(contents)
96 }
97
98 pub fn read_bytes(path: &Path) -> Result<Vec<u8>, io::Error> {
105 let mut file = File::open(path)?;
106 let mut contents = Vec::new();
107 file.read_to_end(&mut contents)?;
108 Ok(contents)
109 }
110
111 pub fn write_string(path: &Path, content: String) -> io::Result<()> {
119 let mut file = File::create(path)?;
120 file.write_all(content.as_bytes())?;
121 Ok(())
122 }
123
124 pub fn append_string(path: &Path, content: String) -> io::Result<()> {
132 let mut file = File::options().append(true).open(path)?;
133 file.write_all(content.as_bytes())?;
134 Ok(())
135 }
136
137 pub fn write_bytes(path: &Path, bytes: &[u8]) -> io::Result<()> {
145 let mut file = File::create(path)?;
146 file.write_all(bytes)?;
147 Ok(())
148 }
149
150 pub fn create_dir_with_parents(dir_path: &str) -> io::Result<()> {
152 fs::create_dir_all(dir_path)
153 }
154
155 pub fn delete_file(file_path: &str) -> io::Result<()> {
157 fs::remove_file(file_path)
158 }
159
160 pub fn delete_directory(dir_path: &str) -> io::Result<()> {
162 fs::remove_dir_all(dir_path)
163 }
164
165 pub fn glob(pattern: &str) -> io::Result<Vec<String>> {
180 let mut results = Vec::new();
181 let r = glob::glob(pattern);
182 if r.is_err() {
183 return Err(io::Error::new(io::ErrorKind::Other, r.err().unwrap().to_string()));
184 }
185 for entry in r.unwrap() {
187 match entry {
188 Ok(path) => {
189 let tmp = path.into_os_string().into_string().unwrap();
190 let tmp = tmp.replace("\\", "/");
191 results.push(tmp);
192 },
193 Err(e) => println!("{:?}", e),
194 }
195 }
196 Ok(results)
197 }
198}
199
200#[cfg(test)]
201mod tests {
202 use super::*;
203 static ROOT_DIR: &str = "d:/tmp/";
204
205 #[test]
206 fn test_glob() {
207 let xx = FileUtil::glob("D:/*/sub_dir").unwrap();
208 println!("{:?}", xx);
209 }
210
211 #[test]
212 fn test_list() {
213 let temp_dir = Path::new(ROOT_DIR);
214 let sub_dir = temp_dir.join("sub_dir");
215 std::fs::create_dir(&sub_dir).expect("Failed to create sub dir");
216 let file_path = sub_dir.join("test_file.txt");
217 std::fs::File::create(&file_path).expect("Failed to create file");
218
219 let result = FileUtil::list(temp_dir, true);
220 assert!(result.contains(&file_path.to_string_lossy().to_string()));
221 }
222
223 #[test]
224 fn test_read_string() -> io::Result<()> {
225 let temp_path = Path::new(ROOT_DIR).join("temp_file.txt");
226 println!("{:?}", temp_path);
227 let mut temp_file = File::options()
228 .write(true)
229 .create(true)
230 .open(temp_path.as_path())?;
231 let content = "test content".to_string();
232 temp_file
233 .write_all(content.as_bytes())
234 .expect("Failed to write to temp file");
235
236 let result = FileUtil::read_string(temp_path.as_path());
237 assert!(result.is_ok());
238 assert_eq!(result.unwrap(), content);
239 Ok(())
240 }
241
242 #[test]
243 fn test_read_bytes() {
244 let temp_path = Path::new(ROOT_DIR).join("temp_file.txt");
245 let mut temp_file = File::options()
246 .write(true)
247 .open(temp_path.as_path())
248 .unwrap();
249 let content = [1, 2, 3];
250 temp_file
251 .write_all(&content)
252 .expect("Failed to write to temp file");
253
254 let result = FileUtil::read_bytes(temp_path.as_path());
255 assert!(result.is_ok());
256 }
257
258 #[test]
259 fn test_write_string() {
260 let temp_path = Path::new(ROOT_DIR).join("temp_file.txt");
261 let _temp_file = File::options().write(true).open(&temp_path).unwrap();
262 let content = "test write content".to_string();
263
264 let result = FileUtil::write_string(&temp_path, content.clone());
265 assert!(result.is_ok());
266
267 let read_result = FileUtil::read_string(&temp_path);
268 assert!(read_result.is_ok());
269 assert_eq!(read_result.unwrap(), content);
270 }
271
272 #[test]
273 fn test_append_string() {
274 let temp_path = Path::new(ROOT_DIR).join("temp_file.txt");
275 let _temp_file = File::open(&temp_path).unwrap();
276 let initial_content = "initial content".to_string();
277 let append_content = " appended content".to_string();
278 FileUtil::write_string(&temp_path, initial_content.clone())
279 .expect("Failed to write initial content");
280
281 let append_result = FileUtil::append_string(&temp_path, append_content.clone());
282 assert!(append_result.is_ok());
283
284 let read_result = FileUtil::read_string(&temp_path);
285 assert!(read_result.is_ok());
286 assert_eq!(read_result.unwrap(), initial_content + &append_content);
287 }
288
289 #[test]
290 fn test_write_bytes() {
291 let temp_path = Path::new(ROOT_DIR).join("temp_file.txt");
292 let _temp_file = File::open(&temp_path).unwrap();
293 let content = [4, 5, 6];
294
295 let result = FileUtil::write_bytes(&temp_path, &content);
296 assert!(result.is_ok());
297
298 let read_result = FileUtil::read_bytes(&temp_path);
299 assert!(read_result.is_ok());
300 assert_eq!(read_result.unwrap(), content);
301 }
302}