dev_tool/
file_util.rs

1//! 文件工具
2use std::fs::{self, File};
3use std::io::{self, Read, Write};
4use std::path::Path;
5
6/// 文件工具结构体
7pub struct FileUtil;
8
9impl FileUtil {
10    /// 罗列指定路径下的子目录及文件。
11    ///
12    /// 参数 `path` 是要罗列内容的目标路径。
13    /// 参数 `recurse` 决定是否以递归方式罗列子文件夹内的内容。
14    ///
15    /// 返回值是一个包含所有子目录及文件路径的 `Vec<String>`。
16    /// 如果在读取目录时发生错误,将返回一个空的 `Vec`。
17    pub fn list(path: &Path, recurse: bool) -> Vec<String> {
18        let mut result = Vec::new();
19        let entries = match fs::read_dir(path) {
20            Ok(entries) => entries,
21            Err(_) => return result,
22        };
23
24        for entry in entries {
25            let entry = match entry {
26                Ok(entry) => entry,
27                Err(_) => continue,
28            };
29            let path = entry.path();
30            if path.is_dir() {
31                if recurse {
32                    result.extend(Self::list(&path, true));
33                }
34                result.push(path.to_string_lossy().to_string());
35            } else {
36                result.push(path.to_string_lossy().to_string());
37            }
38        }
39        result
40    }
41
42    /// 读取本地文件内容并以UTF - 8字符串形式返回。
43    ///
44    /// 参数 `path` 是要读取的文件路径。
45    ///
46    /// 如果文件成功打开并读取,将返回包含文件内容的 `String`。
47    /// 如果在打开或读取文件时发生I/O错误,将返回对应的 `io::Error`。
48    pub fn read_string(path: &Path) -> Result<String, io::Error> {
49        let mut file = File::open(path)?;
50        let mut contents = String::new();
51        file.read_to_string(&mut contents)?;
52        Ok(contents)
53    }
54
55    /// 读取本地文件内容并以字节数组形式返回。
56    ///
57    /// 参数 `path` 是要读取的文件路径。
58    ///
59    /// 如果文件成功打开并读取,将返回包含文件内容的 `Vec<u8>`。
60    /// 如果在打开或读取文件时发生I/O错误,将返回对应的 `io::Error`。
61    pub fn read_bytes(path: &Path) -> Result<Vec<u8>, io::Error> {
62        let mut file = File::open(path)?;
63        let mut contents = Vec::new();
64        file.read_to_end(&mut contents)?;
65        Ok(contents)
66    }
67
68    /// 将给定的字符串内容以覆盖方式写入到指定路径的文本文件。
69    ///
70    /// 参数 `path` 是要写入的文件路径。
71    /// 参数 `content` 是要写入文件的字符串内容。
72    ///
73    /// 如果文件成功创建并写入内容,将返回 `Ok(())`。
74    /// 如果在创建或写入文件时发生I/O错误,将返回对应的 `io::Error`。
75    pub fn write_string(path: &Path, content: String) -> Result<(), io::Error> {
76        let mut file = File::create(path)?;
77        file.write_all(content.as_bytes())?;
78        Ok(())
79    }
80
81    /// 将给定的字符串内容以追加方式写入到指定路径的文件。
82    ///
83    /// 参数 `path` 是要写入的文件路径。
84    /// 参数 `content` 是要追加到文件的字符串内容。
85    ///
86    /// 如果文件成功打开并追加内容,将返回 `Ok(())`。
87    /// 如果在打开或写入文件时发生I/O错误,将返回对应的 `io::Error`。
88    pub fn append_string(path: &Path, content: String) -> Result<(), io::Error> {
89        let mut file = File::options().append(true).open(path)?;
90        file.write_all(content.as_bytes())?;
91        Ok(())
92    }
93
94    /// 将给定的字节数组内容写入到指定路径的文件。
95    ///
96    /// 参数 `path` 是要写入的文件路径。
97    /// 参数 `bytes` 是要写入文件的字节数组内容。
98    ///
99    /// 如果文件成功创建并写入内容,将返回 `Ok(())`。
100    /// 如果在创建或写入文件时发生I/O错误,将返回对应的 `io::Error`。
101    pub fn write_bytes(path: &Path, bytes: &[u8]) -> Result<(), io::Error> {
102        let mut file = File::create(path)?;
103        file.write_all(bytes)?;
104        Ok(())
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111    use std::fs::remove_file;
112    use std::path::PathBuf;
113    static root_dir: &str = "d:/tmp/";
114
115    #[test]
116    fn test_list() {
117        let temp_dir = Path::new(root_dir);
118        let sub_dir = temp_dir.join("sub_dir");
119        std::fs::create_dir(&sub_dir).expect("Failed to create sub dir");
120        let file_path = sub_dir.join("test_file.txt");
121        std::fs::File::create(&file_path).expect("Failed to create file");
122
123        let result = FileUtil::list(temp_dir, true);
124        assert!(result.contains(&file_path.to_string_lossy().to_string()));
125    }
126
127    #[test]
128    fn test_read_string() -> io::Result<()>{
129        let temp_path = Path::new(root_dir).join("temp_file.txt");
130        println!("{:?}", temp_path);
131        let mut temp_file = File::options().write(true).create(true).open(temp_path.as_path())?;
132        let content = "test content".to_string();
133        temp_file.write_all(content.as_bytes()).expect("Failed to write to temp file");
134
135        let result = FileUtil::read_string(temp_path.as_path());
136        assert!(result.is_ok());
137        assert_eq!(result.unwrap(), content);
138        Ok(())
139    }
140
141    #[test]
142    fn test_read_bytes() {
143        let temp_path = Path::new(root_dir).join("temp_file.txt");
144        let mut temp_file = File::options().write(true).open(temp_path.as_path()).unwrap();
145        let content = [1, 2, 3];
146        temp_file.write_all(&content).expect("Failed to write to temp file");
147
148        let result = FileUtil::read_bytes(temp_path.as_path());
149        assert!(result.is_ok());
150    }
151
152    #[test]
153    fn test_write_string() {
154        let temp_path = Path::new(root_dir).join("temp_file.txt");
155        let mut temp_file = File::options().write(true).open(&temp_path).unwrap();
156        let content = "test write content".to_string();
157
158        let result = FileUtil::write_string(&temp_path, content.clone());
159        assert!(result.is_ok());
160
161        let read_result = FileUtil::read_string(&temp_path);
162        assert!(read_result.is_ok());
163        assert_eq!(read_result.unwrap(), content);
164    }
165
166    #[test]
167    fn test_append_string() {
168        let temp_path = Path::new(root_dir).join("temp_file.txt");
169        let mut temp_file = File::open(&temp_path).unwrap();
170        let initial_content = "initial content".to_string();
171        let append_content = " appended content".to_string();
172        FileUtil::write_string(&temp_path, initial_content.clone()).expect("Failed to write initial content");
173
174        let append_result = FileUtil::append_string(&temp_path, append_content.clone());
175        assert!(append_result.is_ok());
176
177        let read_result = FileUtil::read_string(&temp_path);
178        assert!(read_result.is_ok());
179        assert_eq!(read_result.unwrap(), initial_content + &append_content);
180    }
181
182    #[test]
183    fn test_write_bytes() {
184        let temp_path = Path::new(root_dir).join("temp_file.txt");
185        let mut temp_file = File::open(&temp_path).unwrap();
186        let content = [4, 5, 6];
187
188        let result = FileUtil::write_bytes(&temp_path, &content);
189        assert!(result.is_ok());
190
191        let read_result = FileUtil::read_bytes(&temp_path);
192        assert!(read_result.is_ok());
193        assert_eq!(read_result.unwrap(), content);
194    }
195}