oafuncs 0.0.97.15__py3-none-any.whl → 0.0.97.17__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
oafuncs/oa_file.py CHANGED
@@ -1,461 +1,407 @@
1
- #!/usr/bin/env python
2
- # coding=utf-8
3
- """
4
- Author: Liu Kun && 16031215@qq.com
5
- Date: 2024-09-17 15:07:13
6
- LastEditors: Liu Kun && 16031215@qq.com
7
- LastEditTime: 2024-12-13 16:28:56
8
- FilePath: \\Python\\My_Funcs\\OAFuncs\\oafuncs\\oa_file.py
9
- Description:
10
- EditPlatform: vscode
11
- ComputerInfo: XPS 15 9510
12
- SystemInfo: Windows 11
13
- Python Version: 3.11
14
- """
15
-
16
1
  import glob
17
2
  import os
18
3
  import re
19
4
  import shutil
20
-
5
+ from typing import Dict, List, Optional, Union
21
6
 
22
7
  from rich import print
23
8
 
24
9
  __all__ = ["find_file", "link_file", "copy_file", "rename_file", "move_file", "clear_folder", "remove_empty_folder", "remove", "file_size", "mean_size", "make_dir", "replace_content"]
25
10
 
26
11
 
27
- # ** 查找文件,支持通配符
28
- def find_file(parent_path, fname, mode="path"):
29
- """
30
- description:
31
- param {*} parent_path: The parent path where the files are located
32
- param {*} fname: The file name pattern to search for
33
- param {*} mode: 'path' to return the full path of the files, 'file' to return only the file names
34
- return {*} A list of file paths or file names if files are found, None otherwise
12
+ def find_file(parent_dir: Union[str, os.PathLike], file_pattern: str, return_mode: str = "path") -> List[str]:
13
+ """Finds files matching a specified pattern.
14
+
15
+ Args:
16
+ parent_dir: The parent directory where to search for files
17
+ file_pattern: The file name pattern to search for
18
+ return_mode: Return mode, 'path' to return full file paths, 'file' to return only file names. Defaults to 'path'
19
+
20
+ Returns:
21
+ A list of file paths or file names if files are found, otherwise an empty list
35
22
  """
36
23
 
37
- def natural_sort_key(s):
38
- """生成一个用于自然排序的键"""
24
+ def natural_sort_key(s: str) -> List[Union[int, str]]:
25
+ """Generate a key for natural sorting."""
39
26
  return [int(text) if text.isdigit() else text.lower() for text in re.split("([0-9]+)", s)]
40
27
 
41
- # 将parent_path和fname结合成完整的搜索路径
42
- search_pattern = os.path.join(str(parent_path), fname)
43
-
44
- # 使用glob模块查找所有匹配的文件
28
+ search_pattern = os.path.join(str(parent_dir), file_pattern)
45
29
  matched_files = glob.glob(search_pattern)
46
30
 
47
- # 如果没有找到任何文件,则返回False
48
31
  if not matched_files:
49
- return None
32
+ return []
50
33
 
51
- # 在find_files函数中替换natsorted调用
52
34
  matched_files = sorted(matched_files, key=natural_sort_key)
53
35
 
54
- # 根据mode参数决定返回的内容
55
- if mode == "file":
56
- # 只返回文件名
36
+ if return_mode == "file":
57
37
  result = [os.path.basename(file) for file in matched_files]
58
- else: # 默认为'path'
59
- # 返回文件的绝对路径
38
+ else:
60
39
  result = [os.path.abspath(file) for file in matched_files]
61
40
 
62
41
  return result
63
42
 
64
43
 
65
- # ** 创建符号链接,支持通配符
66
- def link_file(src_pattern, dst):
67
- """
68
- # 描述:创建符号链接,支持通配符
69
- # 使用示例
70
- # link_file(r'/data/hejx/liukun/era5/*', r'/data/hejx/liukun/Test/')
71
- # link_file(r'/data/hejx/liukun/era5/py.o*', r'/data/hejx/liukun/Test/py.o')
72
- # link_file(r'/data/hejx/liukun/era5/py.o*', r'/data/hejx/liukun/Test')
73
- param {*} src_pattern # 源文件或目录
74
- param {*} dst # 目标文件或目录
44
+ def link_file(source_pattern: str, destination: str) -> None:
45
+ """Creates symbolic links with wildcard support.
46
+
47
+ Args:
48
+ source_pattern: Source file or directory pattern (supports wildcards)
49
+ destination: Destination file or directory
50
+
51
+ Examples:
52
+ >>> link_file(r'/data/hejx/liukun/era5/*', r'/data/hejx/liukun/Test/')
53
+ >>> link_file(r'/data/hejx/liukun/era5/py.o*', r'/data/hejx/liukun/Test/py.o')
54
+ >>> link_file(r'/data/hejx/liukun/era5/py.o*', r'/data/hejx/liukun/Test')
75
55
  """
76
- src_pattern = str(src_pattern)
77
- # 使用glob.glob来处理可能包含通配符的src
78
- src_files = glob.glob(src_pattern)
56
+ source_pattern = str(source_pattern)
57
+ src_files = glob.glob(source_pattern) if "*" in source_pattern else [source_pattern]
58
+
79
59
  if not src_files:
80
- raise FileNotFoundError("File does not exist: {}".format(src_pattern))
81
-
82
- # 判断dst是路径还是包含文件名的路径
83
- if os.path.isdir(dst):
84
- # 如果dst是路径,则保持源文件的文件名
85
- dst_dir = dst
86
- for src_file in src_files:
87
- src_file_basename = os.path.basename(src_file)
88
- dst_file = os.path.join(dst_dir, src_file_basename)
60
+ print(f"[yellow]No matching files or directories found for:[/yellow] '[bold]{source_pattern}[/bold]'")
61
+ return
62
+
63
+ for src_file in src_files:
64
+ try:
65
+ if os.path.isdir(destination):
66
+ dst_file = os.path.join(destination, os.path.basename(src_file))
67
+ else:
68
+ dst_file = destination
69
+
70
+ os.makedirs(os.path.dirname(dst_file), exist_ok=True)
71
+
89
72
  if os.path.exists(dst_file):
90
73
  os.remove(dst_file)
91
74
  os.symlink(src_file, dst_file)
92
- # print(f"创建符号链接: {src_file} -> {dst_file}")
93
- print(f"Create a symbolic link: {src_file} -> {dst_file}")
94
- else:
95
- # 如果dst包含文件名,则创建链接后重命名
96
- dst_dir = os.path.dirname(dst)
97
- os.makedirs(dst_dir, exist_ok=True)
98
- # 只处理第一个匹配的文件
99
- src_file = src_files[0]
100
- dst_file = dst
101
- if os.path.exists(dst_file):
102
- os.remove(dst_file)
103
- os.symlink(src_file, dst_file)
104
- # print(f"创建符号链接并重命名: {src_file} -> {dst_file}")
105
- print(f"Create a symbolic link and rename: {src_file} -> {dst_file}")
106
-
107
-
108
- # ** 复制文件或目录,支持通配符
109
- def copy_file(src_pattern, dst):
110
- """
111
- # 描述:复制文件或目录,支持通配符
112
- # 使用示例
113
- # copy_file(r'/data/hejx/liukun/era5/py.o*', r'/data/hejx/liukun/Test/py.o')
114
- # copy_file(r'/data/hejx/liukun/era5/py.o*', r'/data/hejx/liukun/Test')
115
- param {*} src_pattern # 源文件或目录
116
- param {*} dst # 目标文件或目录
75
+
76
+ print(f"[green]Successfully created symbolic link:[/green] [bold]{src_file}[/bold] -> [bold]{dst_file}[/bold]")
77
+ except Exception as e:
78
+ print(f"[red]Failed to create symbolic link:[/red] [bold]{src_file}[/bold]. Error: {e}")
79
+
80
+
81
+ def copy_file(source_pattern: str, destination: str) -> None:
82
+ """Copies files or directories with wildcard support.
83
+
84
+ Args:
85
+ source_pattern: Source file or directory pattern (supports wildcards)
86
+ destination: Destination file or directory
87
+
88
+ Examples:
89
+ >>> copy_file(r'/data/hejx/liukun/era5/py.o*', r'/data/hejx/liukun/Test/py.o')
90
+ >>> copy_file(r'/data/hejx/liukun/era5/py.o*', r'/data/hejx/liukun/Test')
117
91
  """
118
- src_pattern = str(src_pattern)
119
- # 使用glob.glob来处理可能包含通配符的src
120
- src_files = glob.glob(src_pattern)
92
+ source_pattern = str(source_pattern)
93
+ src_files = glob.glob(source_pattern) if "*" in source_pattern else [source_pattern]
94
+
121
95
  if not src_files:
122
- raise FileNotFoundError("File does not exist: {}".format(src_pattern))
123
-
124
- # 判断dst是路径还是包含文件名的路径
125
- if os.path.isdir(dst):
126
- # 如果dst是路径,则保持源文件的文件名
127
- dst_dir = dst
128
- for src_file in src_files:
129
- src_file_basename = os.path.basename(src_file)
130
- dst_file = os.path.join(dst_dir, src_file_basename)
96
+ print(f"[yellow]No matching files or directories found for:[/yellow] '[bold]{source_pattern}[/bold]'")
97
+ return
98
+
99
+ for src_file in src_files:
100
+ try:
101
+ if os.path.isdir(destination):
102
+ dst_file = os.path.join(destination, os.path.basename(src_file))
103
+ else:
104
+ dst_file = destination
105
+
106
+ os.makedirs(os.path.dirname(dst_file), exist_ok=True)
107
+
131
108
  if os.path.exists(dst_file):
132
109
  if os.path.isdir(dst_file):
133
110
  shutil.rmtree(dst_file)
134
111
  else:
135
112
  os.remove(dst_file)
113
+
136
114
  if os.path.isdir(src_file):
137
115
  shutil.copytree(src_file, dst_file, symlinks=True)
138
116
  else:
139
117
  shutil.copy2(src_file, dst_file)
140
- print(f"Copy file or directory: {src_file} -> {dst_file}")
141
- else:
142
- # 如果dst包含文件名,则复制后重命名
143
- dst_dir = os.path.dirname(dst)
144
- os.makedirs(dst_dir, exist_ok=True)
145
- # 只处理第一个匹配的文件
146
- src_file = src_files[0]
147
- dst_file = dst
148
- if os.path.exists(dst_file):
149
- if os.path.isdir(dst_file):
150
- shutil.rmtree(dst_file)
151
- else:
152
- os.remove(dst_file)
153
- if os.path.isdir(src_file):
154
- shutil.copytree(src_file, dst_file, symlinks=True)
155
- else:
156
- shutil.copy2(src_file, dst_file)
157
- print(f"Copy and rename file or directory: {src_file} -> {dst_file}")
118
+
119
+ print(f"[green]Successfully copied:[/green] [bold]{src_file}[/bold] -> [bold]{dst_file}[/bold]")
120
+ except Exception as e:
121
+ print(f"[red]Failed to copy:[/red] [bold]{src_file}[/bold]. Error: {e}")
158
122
 
159
123
 
160
- # ** 移动文件或目录,支持通配符
161
- def move_file(src_pattern, dst):
162
- """
163
- # 描述:移动文件或目录,支持通配符
164
- # 使用示例
165
- # move_file(r'/data/hejx/liukun/era5/*', r'/data/hejx/liukun/Test/')
166
- # move_file(r'/data/hejx/liukun/era5/py.o*', r'/data/hejx/liukun/Test/py.o')
167
- # move_file(r'/data/hejx/liukun/era5/py.o*', r'/data/hejx/liukun/Test')
168
- param {*} src_pattern # 源文件或目录
169
- param {*} dst # 目标文件或目录
124
+ def move_file(source_pattern: str, destination: str) -> None:
125
+ """Moves files or directories with wildcard support.
126
+
127
+ Args:
128
+ source_pattern: Source file or directory pattern (supports wildcards)
129
+ destination: Destination file or directory
130
+
131
+ Examples:
132
+ >>> move_file(r'/data/hejx/liukun/era5/*', r'/data/hejx/liukun/Test/')
133
+ >>> move_file(r'/data/hejx/liukun/era5/py.o*', r'/data/hejx/liukun/Test/py.o')
134
+ >>> move_file(r'/data/hejx/liukun/era5/py.o*', r'/data/hejx/liukun/Test')
170
135
  """
171
- src_pattern = str(src_pattern)
172
- # 使用glob.glob来处理可能包含通配符的src
173
- src_files = glob.glob(src_pattern)
136
+ source_pattern = str(source_pattern)
137
+ src_files = glob.glob(source_pattern) if "*" in source_pattern else [source_pattern]
138
+
174
139
  if not src_files:
175
- raise FileNotFoundError("File does not exist: {}".format(src_pattern))
176
-
177
- # 判断dst是路径还是包含文件名的路径
178
- if os.path.isdir(dst):
179
- # 如果dst是路径,则保持源文件的文件名
180
- dst_dir = dst
181
- for src_file in src_files:
182
- src_file_basename = os.path.basename(src_file)
183
- dst_file = os.path.join(dst_dir, src_file_basename)
140
+ print(f"[yellow]No matching files or directories found for:[/yellow] '[bold]{source_pattern}[/bold]'")
141
+ return
142
+
143
+ for src_file in src_files:
144
+ try:
145
+ if os.path.isdir(destination):
146
+ dst_file = os.path.join(destination, os.path.basename(src_file))
147
+ else:
148
+ dst_file = destination
149
+
150
+ os.makedirs(os.path.dirname(dst_file), exist_ok=True)
151
+
184
152
  if os.path.exists(dst_file):
185
153
  if os.path.isdir(dst_file):
186
154
  shutil.rmtree(dst_file)
187
155
  else:
188
156
  os.remove(dst_file)
189
157
  shutil.move(src_file, dst_file)
190
- print(f"Move file or directory: {src_file} -> {dst_file}")
191
- else:
192
- # 如果dst包含文件名,则移动后重命名
193
- dst_dir = os.path.dirname(dst)
194
- os.makedirs(dst_dir, exist_ok=True)
195
- # 只处理第一个匹配的文件
196
- src_file = src_files[0]
197
- dst_file = dst
198
- if os.path.exists(dst_file):
199
- if os.path.isdir(dst_file):
200
- shutil.rmtree(dst_file)
201
- else:
202
- os.remove(dst_file)
203
- shutil.move(src_file, dst_file)
204
- print(f"Move and rename file or directory: {src_file} -> {dst_file}")
205
158
 
159
+ print(f"[green]Successfully moved:[/green] [bold]{src_file}[/bold] -> [bold]{dst_file}[/bold]")
160
+ except Exception as e:
161
+ print(f"[red]Failed to move:[/red] [bold]{src_file}[/bold]. Error: {e}")
206
162
 
207
- # ** 重命名文件,支持通配符
208
- def rename_file(directory, old_str, new_str):
209
- """
210
- # 描述:重命名目录下的文件,支持通配符
211
- # 使用示例
212
- directory_path = r"E:\\windfarm\\CROCO_FILES"
213
- old_str = "croco"
214
- new_str = "roms"
215
- rename_file(directory_path, old_str, new_str)
216
- param {*} directory # 目录
217
- param {*} old_str # 要替换的字符串
218
- param {*} new_str # 新字符串
219
- """
220
- # 获取目录下的所有文件
221
- files = os.listdir(directory)
222
-
223
- # 构建正则表达式以匹配要替换的字符串
224
- pattern = re.compile(re.escape(old_str))
225
-
226
- # 遍历目录下的文件
227
- for filename in files:
228
- # 检查文件名中是否包含要替换的字符串
229
- if pattern.search(filename):
230
- # 构建新的文件名
231
- new_filename = pattern.sub(new_str, filename)
232
163
 
233
- # 构建旧文件的完整路径
234
- old_path = os.path.join(directory, filename)
164
+ def rename_file(target_dir: str, old_substring: str, new_substring: str) -> None:
165
+ """Renames files in a directory by replacing specified string patterns.
235
166
 
236
- # 构建新文件的完整路径
237
- new_path = os.path.join(directory, new_filename)
167
+ Recursively processes all files in the directory, replacing parts of filenames
168
+ that contain the specified string.
238
169
 
239
- # 重命名文件
240
- os.rename(old_path, new_path)
241
- print(f"Rename file: {old_path} -> {new_path}")
170
+ Args:
171
+ target_dir: The directory path to process
172
+ old_substring: The string to be replaced
173
+ new_substring: The new string to replace with
174
+
175
+ Examples:
176
+ >>> directory_path = r"E:\\windfarm\\CROCO_FILES"
177
+ >>> old_substring = "croco"
178
+ >>> new_substring = "roms"
179
+ >>> rename_file(directory_path, old_substring, new_substring)
180
+ """
181
+ for root, _, files in os.walk(target_dir):
182
+ pattern = re.compile(re.escape(old_substring))
242
183
 
184
+ for filename in files:
185
+ if pattern.search(filename):
186
+ new_filename = pattern.sub(new_substring, filename)
187
+ old_path = os.path.join(root, filename)
188
+ new_path = os.path.join(root, new_filename)
189
+ os.rename(old_path, new_path)
190
+ print(f"[green]Rename file:[/green] [bold]{old_path}[/bold] -> [bold]{new_path}[/bold]")
243
191
 
244
- # ** 创建路径
245
- def make_dir(directory):
246
- """
247
- Description:
248
- Create a directory if it does not exist
249
192
 
250
- Parameters:
251
- directory: The directory path to create
193
+ def make_dir(target_dir: Union[str, os.PathLike]) -> None:
194
+ """Creates a directory if it does not exist.
252
195
 
253
- Returns:
254
- None
196
+ Args:
197
+ target_dir: The directory path to create
255
198
 
256
- Example:
257
- make_dir(r"E:\\Data\\2024\\09\\17\\var1")
199
+ Examples:
200
+ >>> make_dir(r"E:\\Data\\2024\\09\\17\\var1")
258
201
  """
259
- directory = str(directory)
260
- if os.path.exists(directory):
261
- print(f"Directory already exists: {directory}")
202
+ target_dir = str(target_dir)
203
+ if os.path.exists(target_dir):
204
+ print(f"[blue]Directory already exists:[/blue] [bold]{target_dir}[/bold]")
262
205
  return
263
206
  else:
264
- os.makedirs(directory, exist_ok=True)
265
- print(f"Created directory: {directory}")
207
+ os.makedirs(target_dir, exist_ok=True)
208
+ print(f"[green]Created directory:[/green] [bold]{target_dir}[/bold]")
266
209
 
267
210
 
268
- # ** 清空文件夹
269
- def clear_folder(folder_path):
270
- """
271
- # 描述:清空文件夹
272
- # 使用示例
273
- clear_folder(r'E:\\Data\\2024\\09\\17\\var1')
274
- param {*} folder_path # 文件夹路径
211
+ def clear_folder(target_folder: Union[str, os.PathLike]) -> None:
212
+ """Clears all contents of the specified folder.
213
+
214
+ Removes all files and subdirectories within the folder, while preserving the folder itself.
215
+
216
+ Args:
217
+ target_folder: Path of the folder to clear
218
+
219
+ Examples:
220
+ >>> clear_folder(r'E:\\Data\\2024\\09\\17\\var1')
275
221
  """
276
- folder_path = str(folder_path)
277
- if os.path.exists(folder_path):
222
+ target_folder = str(target_folder)
223
+ if os.path.exists(target_folder):
278
224
  try:
279
- # 遍历文件夹中的所有文件和子文件夹
280
- for filename in os.listdir(folder_path):
281
- file_path = os.path.join(folder_path, filename)
282
- # 判断是文件还是文件夹
225
+ for filename in os.listdir(target_folder):
226
+ file_path = os.path.join(target_folder, filename)
283
227
  if os.path.isfile(file_path) or os.path.islink(file_path):
284
- os.unlink(file_path) # 删除文件或链接
228
+ os.unlink(file_path)
285
229
  elif os.path.isdir(file_path):
286
- shutil.rmtree(file_path) # 删除子文件夹
287
- # print(f"成功清空文件夹: {folder_path}")
288
- print(f"Successfully cleared the folder: {folder_path}")
230
+ shutil.rmtree(file_path)
231
+ print(f"[green]Successfully cleared the folder:[/green] [bold]{target_folder}[/bold]")
289
232
  except Exception as e:
290
- # print(f"清空文件夹失败: {folder_path}")
291
- print(f"Failed to clear the folder: {folder_path}")
292
- print(e)
233
+ print(f"[red]Failed to clear the folder:[/red] [bold]{target_folder}[/bold]")
234
+ print(f"[red]{e}[/red]")
293
235
 
294
236
 
295
- # ** 清理空文件夹
296
- def remove_empty_folder(path, print_info=1):
297
- """
298
- # 描述:清理空文件夹
299
- # 使用示例
300
- remove_empty_folder(r'E:\\Data\\2024\\09\\17', print_info=1)
301
- param {*} path # 文件夹路径
302
- param {*} print_info # 是否打印信息
237
+ def remove_empty_folder(target_path: Union[str, os.PathLike], verbose: int = 1) -> None:
238
+ """Recursively removes all empty folders under the specified path.
239
+
240
+ Args:
241
+ target_path: The folder path to process
242
+ verbose: Whether to print processing information, 1 means print, 0 means no print
243
+
244
+ Examples:
245
+ >>> remove_empty_folder(r'E:\\Data\\2024\\09\\17', verbose=1)
303
246
  """
304
- path = str(path)
305
- # 遍历当前目录下的所有文件夹和文件
306
- for root, dirs, files in os.walk(path, topdown=False):
307
- # 遍历文件夹列表
247
+ target_path = str(target_path)
248
+ for root, dirs, files in os.walk(target_path, topdown=False):
308
249
  for folder in dirs:
309
250
  folder_path = os.path.join(root, folder)
310
- # 判断文件是否有权限访问
311
251
  try:
312
252
  os.listdir(folder_path)
313
253
  except OSError:
314
254
  continue
315
- # 判断文件夹是否为空
316
255
  if not os.listdir(folder_path):
317
- # 删除空文件夹
318
256
  try:
319
257
  os.rmdir(folder_path)
320
- print(f"Deleted empty folder: {folder_path}")
258
+ print(f"[green]Deleted empty folder:[/green] [bold]{folder_path}[/bold]")
321
259
  except OSError:
322
- if print_info:
323
- print(f"Skipping protected folder: {folder_path}")
260
+ if verbose:
261
+ print(f"[yellow]Skipping protected folder:[/yellow] [bold]{folder_path}[/bold]")
324
262
  pass
325
263
 
326
264
 
327
- # ** 删除相关文件,可使用通配符
328
- def remove(pattern):
329
- """
330
- Delete files or directories that match the given wildcard pattern.
331
-
332
- Parameters:
333
- pattern : str
334
- File path or string containing wildcards. For example:
335
- - r'E:\\Code\\Python\\Model\\WRF\\Radar2\\bzip2-radar-0*'
336
- - 'bzip2-radar-0*' (assuming you are already in the target directory)
265
+ def remove(target_pattern: str) -> None:
266
+ """Deletes files or directories that match the given wildcard pattern.
337
267
 
338
- Usage examples:
339
- remove(r'E:\\Code\\Python\\Model\\WRF\\Radar2\\bzip2-radar-0*')
340
- or
341
- os.chdir(r'E:\\Code\\Python\\Model\\WRF\\Radar2')
342
- remove('bzip2-radar-0*')
268
+ Args:
269
+ target_pattern: File path or string containing wildcards
343
270
 
344
- last updated: 2025-01-10 11:49:13
271
+ Examples:
272
+ >>> remove(r'E:\\Code\\Python\\Model\\WRF\\Radar2\\bzip2-radar-0*')
273
+ >>> # or, assuming you are already in the target directory
274
+ >>> # os.chdir(r'E:\\Code\\Python\\Model\\WRF\\Radar2')
275
+ >>> # remove('bzip2-radar-0*')
345
276
  """
346
- pattern = str(pattern)
347
-
348
- # Use glob.glob to get all matching files or directories
349
- file_list = glob.glob(pattern)
277
+ target_pattern = str(target_pattern)
278
+ file_list = glob.glob(target_pattern) if "*" in target_pattern else [target_pattern]
350
279
 
351
280
  if not file_list:
352
- print(f"No files or directories found matching '{pattern}'.")
281
+ print(f"[yellow]No matching files or directories found for:[/yellow] '[bold]{target_pattern}[/bold]'")
353
282
  return
354
283
 
355
284
  for file_path in file_list:
356
- if os.path.exists(file_path):
357
- try:
358
- if os.path.isdir(file_path):
359
- shutil.rmtree(file_path)
360
- print(f"Successfully deleted directory: {file_path}")
361
- else:
362
- os.remove(file_path)
363
- print(f"Successfully deleted file: {file_path}")
364
- except Exception as e:
365
- print(f"Deletion failed: {file_path}")
366
- print(f"Error message: {e}")
367
- else:
368
- print(f"File or directory does not exist: {file_path}")
285
+ try:
286
+ if os.path.isdir(file_path) or os.path.isfile(file_path) or os.path.islink(file_path):
287
+ (shutil.rmtree if os.path.isdir(file_path) else os.remove)(file_path)
288
+ print(f"[green]Successfully deleted:[/green] [bold]{file_path}[/bold]")
289
+ else:
290
+ print(f"[yellow]Skipping unknown file type:[/yellow] [bold]{file_path}[/bold]")
291
+ except Exception as e:
292
+ print(f"[red]Failed to delete:[/red] [bold]{file_path}[/bold]. Error: {e}")
369
293
 
370
294
 
371
- # ** 获取文件大小
372
- def file_size(file_path, unit="KB"):
373
- """
374
- Description: 获取文件大小
295
+ def file_size(file_path: Union[str, os.PathLike], unit: str = "KB", verbose: bool = False) -> float:
296
+ """Gets the size of a file in the specified unit.
375
297
 
376
298
  Args:
377
- file_path: 文件路径
378
- unit: 单位(PBTBGBMBKB
299
+ file_path: Path to the file
300
+ unit: Size unit, can be PB, TB, GB, MB, KB, or B
301
+ verbose: Whether to display information about the file size
379
302
 
380
303
  Returns:
381
- 文件大小(单位:PB、TB、GB、MB、KB)
382
- """
383
- # 检查文件是否存在
384
- if not os.path.exists(file_path):
385
- # return "文件不存在"
386
- # print(f"文件不存在: {file_path}\n返回0.0")
387
- print(f"File does not exist: {file_path}\nReturn 0.0")
388
- return 0.0
389
-
390
- # 获取文件大小(字节)
391
- file_size = os.path.getsize(file_path)
304
+ The file size in the specified unit, or 0.0 if file doesn't exist or unit is invalid
392
305
 
393
- # 单位转换字典
394
- unit_dict = {"PB": 1024**5, "TB": 1024**4, "GB": 1024**3, "MB": 1024**2, "KB": 1024}
306
+ Examples:
307
+ >>> size = file_size("myfile.txt", "MB")
308
+ >>> print(f"File size is {size} MB")
309
+ """
310
+ unit = unit.upper()
311
+ unit_dict = {"PB": 1024**5, "TB": 1024**4, "GB": 1024**3, "MB": 1024**2, "KB": 1024, "B": 1}
395
312
 
396
- # 检查传入的单位是否合法
397
313
  if unit not in unit_dict:
398
- # return "单位不合法,请选择PB、TB、GB、MB、KB中的一个"
399
- # print("单位不合法,请选择PBTBGBMBKB中的一个\n返回0.0")
400
- print("Invalid unit, please choose one of PB, TB, GB, MB, KB\nReturn 0.0")
314
+ if verbose:
315
+ print("[yellow]Invalid unit, please choose one of PB, TB, GB, MB, KB, B[/yellow]")
401
316
  return 0.0
402
317
 
403
- # 转换文件大小到指定单位
404
- converted_size = file_size / unit_dict[unit]
318
+ if not os.path.isfile(file_path):
319
+ if verbose:
320
+ print(f"[yellow]Invalid file path or not a file:[/yellow] [bold]{file_path}[/bold]")
321
+ return 0.0
405
322
 
406
- return converted_size
323
+ try:
324
+ size_in_bytes = os.path.getsize(file_path)
325
+ size = size_in_bytes / unit_dict[unit]
326
+ if verbose:
327
+ print(f"[green]File size:[/green] [bold]{size:.2f} {unit}[/bold]")
328
+ return size
329
+ except (OSError, IOError) as e:
330
+ if verbose:
331
+ print(f"[red]Error getting file size:[/red] {e}")
332
+ return 0.0
407
333
 
408
334
 
409
- # ** 计算文件夹下指定相关文件的平均大小
410
- def mean_size(parent_path, fname, max_num=None, unit="KB"):
411
- """
412
- Description:
413
- Calculate the average size of the specified related files in the folder
335
+ def mean_size(parent_dir: Union[str, os.PathLike], file_pattern: str, max_files: Optional[int] = None, unit: str = "KB") -> float:
336
+ """Calculates the average size of specified files in a folder.
414
337
 
415
- Parameters:
416
- parent_path: The parent path where the files are located
417
- fname: The file name pattern to search for
418
- max_num: The maximum number of files to search for
419
- unit: The unit of the file size, default is "KB"
338
+ Args:
339
+ parent_dir: The parent directory where the files are located
340
+ file_pattern: The file name pattern to search for
341
+ max_files: Maximum number of files to process, process all matching files if None
342
+ unit: File size unit, defaults to "KB"
420
343
 
421
344
  Returns:
422
- The average size
345
+ Average file size. Returns 0.0 if no files are found or all files have size 0
346
+
347
+ Examples:
348
+ >>> avg_size = mean_size("/data/logs", "*.log", max_files=10, unit="MB")
349
+ >>> print(f"Average log file size is {avg_size} MB")
423
350
  """
424
- flist = find_file(parent_path, fname)
425
- if flist:
426
- if max_num:
427
- flist = flist[: int(max_num)]
428
- size_list = [file_size(f, unit) for f in flist if file_size(f, unit) > 0]
429
- if size_list:
430
- return sum(size_list) / len(size_list)
431
- else:
432
- return 0.0
433
- else:
351
+ # 获取文件列表
352
+ flist = find_file(parent_dir, file_pattern)
353
+ if not flist:
354
+ print(f"[yellow]No files found matching pattern:[/yellow] [bold]{file_pattern}[/bold] in [bold]{parent_dir}[/bold]")
434
355
  return 0.0
435
356
 
357
+ # 处理最大文件数限制
358
+ if max_files is not None:
359
+ try:
360
+ max_files = int(max_files)
361
+ if max_files > 0:
362
+ flist = flist[:max_files]
363
+ else:
364
+ print("[yellow]max_files must be positive, using all files[/yellow]")
365
+ except (ValueError, TypeError):
366
+ print(f"[yellow]Invalid max_files value:[/yellow] [bold]{max_files}[/bold], using all files")
367
+
368
+ # 获取每个文件的大小并过滤掉大小为0的文件
369
+ size_list = [file_size(f, unit) for f in flist]
370
+ valid_sizes = [size for size in size_list if size > 0]
371
+
372
+ # 计算平均值
373
+ if valid_sizes:
374
+ avg_size = sum(valid_sizes) / len(valid_sizes)
375
+ if len(valid_sizes) < len(size_list):
376
+ print(f"[blue]Note:[/blue] {len(size_list) - len(valid_sizes)} files were skipped (size 0 or error)")
377
+ return avg_size
378
+ else:
379
+ print("[yellow]No valid files with size > 0 found[/yellow]")
380
+ return 0.0
436
381
 
437
- def replace_content(source_file, content_dict, key_value=False, target_dir=None, new_name=None):
438
- """
439
- 直接替换文件中的指定内容并保存到新路径
440
382
 
441
- 参数:
442
- source_file: 源文件路径
443
- target_dir: 目标目录路径
444
- content_dict: 要替换的内容字典 {旧内容: 新内容}
445
- key_value: 是否按键值对方式替换参数
383
+ def replace_content(source_file: Union[str, os.PathLike], replacements: Dict[str, str], use_key_value: bool = False, target_dir: Optional[Union[str, os.PathLike]] = None, new_filename: Optional[str] = None) -> None:
384
+ """Directly replaces specified content in a file and saves to a new path.
446
385
 
447
- 返回:
448
- bool: 替换是否成功
386
+ Args:
387
+ source_file: Path to the source file
388
+ replacements: Dictionary of content to replace {old_content: new_content}
389
+ use_key_value: Whether to replace parameters as key-value pairs
390
+ target_dir: Target directory path, uses the source file's directory if None
391
+ new_filename: New file name, keeps the original file name if None
392
+
393
+ Examples:
394
+ >>> replace_content("config.txt", {"old_value": "new_value"})
395
+ >>> replace_content("template.xml", {"name": "John", "age": "30"}, use_key_value=True)
449
396
  """
450
- from ._script.replace_file_concent import replace_direct_content
397
+ from ._script.replace_file_content import replace_direct_content
398
+
451
399
  if target_dir is None:
452
400
  target_dir = os.path.dirname(source_file)
453
- replace_direct_content(source_file, target_dir, content_dict, key_value=key_value, new_name=new_name)
401
+ replace_direct_content(source_file, target_dir, replacements, key_value=use_key_value, new_name=new_filename)
454
402
 
455
403
 
456
404
  if __name__ == "__main__":
457
- # newpath = make_folder('D:/Data/2024/09/17/', 'var1', clear=1)
458
- # print(newpath)
459
405
  pass
460
406
 
461
407
  remove(r"I:\\Delete\\test\\*")