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
166#[cfg(test)]
167mod tests {
168 use super::*;
169 static ROOT_DIR: &str = "d:/tmp/";
170
171 #[test]
172 fn test_list() {
173 let temp_dir = Path::new(ROOT_DIR);
174 let sub_dir = temp_dir.join("sub_dir");
175 std::fs::create_dir(&sub_dir).expect("Failed to create sub dir");
176 let file_path = sub_dir.join("test_file.txt");
177 std::fs::File::create(&file_path).expect("Failed to create file");
178
179 let result = FileUtil::list(temp_dir, true);
180 assert!(result.contains(&file_path.to_string_lossy().to_string()));
181 }
182
183 #[test]
184 fn test_read_string() -> io::Result<()> {
185 let temp_path = Path::new(ROOT_DIR).join("temp_file.txt");
186 println!("{:?}", temp_path);
187 let mut temp_file = File::options()
188 .write(true)
189 .create(true)
190 .open(temp_path.as_path())?;
191 let content = "test content".to_string();
192 temp_file
193 .write_all(content.as_bytes())
194 .expect("Failed to write to temp file");
195
196 let result = FileUtil::read_string(temp_path.as_path());
197 assert!(result.is_ok());
198 assert_eq!(result.unwrap(), content);
199 Ok(())
200 }
201
202 #[test]
203 fn test_read_bytes() {
204 let temp_path = Path::new(ROOT_DIR).join("temp_file.txt");
205 let mut temp_file = File::options()
206 .write(true)
207 .open(temp_path.as_path())
208 .unwrap();
209 let content = [1, 2, 3];
210 temp_file
211 .write_all(&content)
212 .expect("Failed to write to temp file");
213
214 let result = FileUtil::read_bytes(temp_path.as_path());
215 assert!(result.is_ok());
216 }
217
218 #[test]
219 fn test_write_string() {
220 let temp_path = Path::new(ROOT_DIR).join("temp_file.txt");
221 let _temp_file = File::options().write(true).open(&temp_path).unwrap();
222 let content = "test write content".to_string();
223
224 let result = FileUtil::write_string(&temp_path, content.clone());
225 assert!(result.is_ok());
226
227 let read_result = FileUtil::read_string(&temp_path);
228 assert!(read_result.is_ok());
229 assert_eq!(read_result.unwrap(), content);
230 }
231
232 #[test]
233 fn test_append_string() {
234 let temp_path = Path::new(ROOT_DIR).join("temp_file.txt");
235 let _temp_file = File::open(&temp_path).unwrap();
236 let initial_content = "initial content".to_string();
237 let append_content = " appended content".to_string();
238 FileUtil::write_string(&temp_path, initial_content.clone())
239 .expect("Failed to write initial content");
240
241 let append_result = FileUtil::append_string(&temp_path, append_content.clone());
242 assert!(append_result.is_ok());
243
244 let read_result = FileUtil::read_string(&temp_path);
245 assert!(read_result.is_ok());
246 assert_eq!(read_result.unwrap(), initial_content + &append_content);
247 }
248
249 #[test]
250 fn test_write_bytes() {
251 let temp_path = Path::new(ROOT_DIR).join("temp_file.txt");
252 let _temp_file = File::open(&temp_path).unwrap();
253 let content = [4, 5, 6];
254
255 let result = FileUtil::write_bytes(&temp_path, &content);
256 assert!(result.is_ok());
257
258 let read_result = FileUtil::read_bytes(&temp_path);
259 assert!(read_result.is_ok());
260 assert_eq!(read_result.unwrap(), content);
261 }
262}