oafuncs 0.0.97.16__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/_script/netcdf_modify.py +10 -2
- oafuncs/oa_cmap.py +211 -95
- oafuncs/oa_data.py +157 -218
- oafuncs/oa_date.py +71 -37
- oafuncs/oa_down/hycom_3hourly.py +208 -319
- oafuncs/oa_down/hycom_3hourly_20250407.py +1295 -0
- oafuncs/oa_down/idm.py +4 -4
- oafuncs/oa_draw.py +224 -124
- oafuncs/oa_file.py +279 -333
- oafuncs/oa_help.py +10 -0
- oafuncs/oa_nc.py +197 -164
- oafuncs/oa_python.py +51 -25
- oafuncs/oa_tool.py +61 -22
- {oafuncs-0.0.97.16.dist-info → oafuncs-0.0.97.17.dist-info}/METADATA +1 -1
- {oafuncs-0.0.97.16.dist-info → oafuncs-0.0.97.17.dist-info}/RECORD +19 -18
- /oafuncs/_script/{replace_file_concent.py → replace_file_content.py} +0 -0
- {oafuncs-0.0.97.16.dist-info → oafuncs-0.0.97.17.dist-info}/WHEEL +0 -0
- {oafuncs-0.0.97.16.dist-info → oafuncs-0.0.97.17.dist-info}/licenses/LICENSE.txt +0 -0
- {oafuncs-0.0.97.16.dist-info → oafuncs-0.0.97.17.dist-info}/top_level.txt +0 -0
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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
-
|
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
|
32
|
+
return []
|
50
33
|
|
51
|
-
# 在find_files函数中替换natsorted调用
|
52
34
|
matched_files = sorted(matched_files, key=natural_sort_key)
|
53
35
|
|
54
|
-
|
55
|
-
if mode == "file":
|
56
|
-
# 只返回文件名
|
36
|
+
if return_mode == "file":
|
57
37
|
result = [os.path.basename(file) for file in matched_files]
|
58
|
-
else:
|
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
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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
|
-
|
77
|
-
|
78
|
-
|
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
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
93
|
-
print(f"
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
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
|
-
|
119
|
-
|
120
|
-
|
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
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
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
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
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
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
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
|
-
|
172
|
-
|
173
|
-
|
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
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
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
|
-
|
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
|
-
|
167
|
+
Recursively processes all files in the directory, replacing parts of filenames
|
168
|
+
that contain the specified string.
|
238
169
|
|
239
|
-
|
240
|
-
|
241
|
-
|
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
|
-
|
251
|
-
|
193
|
+
def make_dir(target_dir: Union[str, os.PathLike]) -> None:
|
194
|
+
"""Creates a directory if it does not exist.
|
252
195
|
|
253
|
-
|
254
|
-
|
196
|
+
Args:
|
197
|
+
target_dir: The directory path to create
|
255
198
|
|
256
|
-
|
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
|
-
|
260
|
-
if os.path.exists(
|
261
|
-
print(f"Directory already exists: {
|
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(
|
265
|
-
print(f"Created 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
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
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
|
-
|
277
|
-
if os.path.exists(
|
222
|
+
target_folder = str(target_folder)
|
223
|
+
if os.path.exists(target_folder):
|
278
224
|
try:
|
279
|
-
|
280
|
-
|
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
|
-
|
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
|
-
|
291
|
-
print(f"
|
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
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
339
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
357
|
-
|
358
|
-
if os.path.isdir(file_path)
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
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
|
-
|
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
|
-
|
378
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
399
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
unit:
|
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
|
-
|
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
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
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
|
-
|
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
|
-
|
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.
|
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,
|
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\\*")
|