吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1207|回复: 7
收起左侧

[Windows] 批量生成文件以及修改文件前缀及后缀工具

[复制链接]
zwjtr93 发表于 2025-4-2 02:51
批量生成空白文件以及修改文件前缀及后缀工具,具体功能如下图所示(能根据设定的文件名,数量来递增生成文件,前缀的文件名不是必填项,如不填写前缀默认根据数量编号生成文件前缀名),主要是我写小说时批量生成空白章节文件用的,下一楼会分享python代码需要增添功能的自行修改(如前缀编号是默认添加的,如不需要请自行修改代码。)。 QQ20250402-024208.png QQ20250402-024228.png
下载地址:
https://wwlo.lanzouo.com/iYGvD2seqhbe
密码:bqxm

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
jaffa + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| zwjtr93 发表于 2025-4-2 02:51
以下为源码:
[Python] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
import tkinter as tk
from tkinter import ttk # 使用主题控件,外观更好
from tkinter import filedialog, messagebox, scrolledtext
import os
import sys
import re
import logging
from datetime import datetime # 仍然保留,以防未来需要时间戳,但文件名不需要了
try:
    import docx
    DOCX_ENABLED = True
except ImportError:
    DOCX_ENABLED = False
 
# --- 全局变量或常量 ---
APP_NAME = "批量生成文件以及修改文件前缀及后缀工具"
 
# --- 1. 日志处理 ---
# 自定义日志 Handler,将日志记录发送到 tkinter Text 或 ScrolledText 控件
class TextHandler(logging.Handler):
    def __init__(self, text_widget):
        logging.Handler.__init__(self)
        self.text_widget = text_widget
 
    def emit(self, record):
        msg = self.format(record)
        def append():
            # 在 Text 控件的末尾插入日志消息
            self.text_widget.configure(state='normal') # 允许编辑以插入文本
            self.text_widget.insert(tk.END, msg + '\n') # 插入消息和换行符
            self.text_widget.configure(state='disabled') # 重新设为只读
            self.text_widget.yview(tk.END) # 自动滚动到底部
        # 重要:必须使用 `schedule` 或 `after` 来确保从主线程更新 GUI
        self.text_widget.after(0, append)
 
# --- 2. 后端核心逻辑 (保持不变) ---
# 注意:这些函数现在主要通过 logging 输出信息,并通过返回值或异常传递结果
 
def backend_create_files(folder_path, count, start_num, prefix, suffix):
    """
    后端逻辑:批量生成文件。
    返回 (成功数量, 跳过数量)
    通过 logging 报告详细信息和错误。
    """
    logging.info(f"--- 开始生成任务 (后端) ---")
    logging.info(f"配置: 文件夹='{folder_path}', 数量={count}, 起始={start_num}, 前缀='{prefix}', 后缀='{suffix}'")
 
    generated_count = 0
    skipped_count = 0
 
    if not os.path.isdir(folder_path):
        logging.error(f"目标文件夹 '{folder_path}' 不存在或无效。")
        return (0, count) # 全部跳过
 
    if not suffix.startswith('.'):
        suffix = '.' + suffix
        logging.info(f"后缀名自动修正为 '{suffix}'")
 
    is_docx = suffix.lower() == '.docx'
 
    if is_docx and not DOCX_ENABLED:
        logging.warning("无法导入 'python-docx' 库,将尝试创建名为 .docx 的空文件。")
    elif is_docx and DOCX_ENABLED:
        logging.info("检测到 .docx 后缀,使用 'python-docx' 创建标准文档。")
 
    for i in range(count):
        current_num = start_num + i
        file_name = f"{prefix}{current_num}{suffix}" if prefix else f"{current_num}{suffix}"
        full_path = os.path.join(folder_path, file_name)
 
        if os.path.exists(full_path):
            logging.warning(f"文件 '{file_name}' 已存在,跳过。")
            skipped_count += 1
            continue
 
        try:
            if is_docx and DOCX_ENABLED:
                document = docx.Document()
                document.save(full_path)
                logging.info(f"成功: 标准 .docx '{file_name}'")
            else:
                with open(full_path, 'a') as f:
                    pass
                if is_docx:
                     logging.warning(f"创建: 空文件 '{file_name}' (非标准 Word)。")
                else:
                     logging.info(f"成功: 空文件 '{file_name}'")
            generated_count += 1
        except OSError as e:
            logging.error(f"失败: 无法创建 '{file_name}' (OS错误)。原因: {e}")
            skipped_count += 1
        except Exception as e:
             logging.error(f"失败: 创建 .docx '{file_name}' 出错。原因: {e}")
             skipped_count += 1
 
    logging.info(f"--- 生成任务完成 (后端) ---")
    logging.info(f"成功生成 {generated_count},跳过 {skipped_count}。")
    return (generated_count, skipped_count)
 
def backend_build_rename_plan(folder_path, rename_type, params):
    """
    后端逻辑:根据类型和参数构建重命名计划。
    Args:
        folder_path (str): 目标文件夹。
        rename_type (str): 'suffix', 'prefix_part', 'regex'。
        params (dict): 包含所需参数的字典,例如:
                       {'old_suffix': '.txt', 'new_suffix': '.md'}
                       {'old_part': 'Copy', 'new_part': 'Backup'}
                       {'pattern': re.compile object, 'replacement': r'Num_\1'}
    Returns:
        list: [(old_path, new_path), ...] 或 None 如果出错。
        通过 logging 报告错误。
    """
    logging.info(f"--- 开始构建重命名计划 (后端) ---")
    logging.info(f"配置: 文件夹='{folder_path}', 类型='{rename_type}', 参数={params}")
    rename_plan = []
 
    if not os.path.isdir(folder_path):
        logging.error(f"目标文件夹 '{folder_path}' 不存在或无效。")
        return None
 
    try:
        items = os.listdir(folder_path)
    except OSError as e:
        logging.error(f"无法访问文件夹 '{folder_path}'。原因: {e}")
        return None
 
    for item_name in items:
        old_path = os.path.join(folder_path, item_name)
        if not os.path.isfile(old_path):
            continue # 只处理文件
 
        base_name, suffix = os.path.splitext(item_name)
        new_name = None
 
        try:
            if rename_type == 'suffix':
                old_s = params['old_suffix']
                new_s = params['new_suffix']
                # 使用 endswith 进行后缀匹配,确保只匹配后缀
                if item_name.lower().endswith(old_s.lower()):
                     # 使用原始 base_name 确保大小写保留
                    new_name = base_name + new_s
            elif rename_type == 'prefix_part':
                old_p = params['old_part']
                new_p = params['new_part']
                if old_p in base_name:
                    new_base_name = base_name.replace(old_p, new_p)
                    if new_base_name != base_name:
                        new_name = new_base_name + suffix
            elif rename_type == 'regex':
                pattern = params['pattern'] # 已经是编译好的 re 对象
                replacement = params['replacement']
                # 使用 search 在 base_name 中查找匹配
                if pattern.search(base_name):
                     # 使用 sub 进行替换
                    new_base_name = pattern.sub(replacement, base_name)
                    if new_base_name != base_name: # 确保有变化
                        new_name = new_base_name + suffix
 
            if new_name: # 如果成功生成了新名字
                new_path = os.path.join(folder_path, new_name)
                rename_plan.append((old_path, new_path))
 
        except KeyError as e:
            logging.error(f"构建计划时缺少参数: {e}")
            return None # 参数错误,中止计划构建
        except Exception as e: # 捕获其他潜在错误,如 re 错误(虽然已预编译)
            logging.error(f"处理文件 '{item_name}' 时出错: {e}")
            # 可以选择跳过这个文件继续,或者中止,这里选择继续
            continue
 
    logging.info(f"计划构建完成,共找到 {len(rename_plan)} 个可能重命名的文件。")
    return rename_plan
 
 
def backend_execute_rename(rename_plan):
    """
    后端逻辑:执行重命名计划。
    Args:
        rename_plan (list): [(old_path, new_path), ...]
    Returns:
        (成功数量, 跳过数量, 错误数量)
    """
    renamed_count = 0
    skipped_count = 0
    error_count = 0
    logging.info(f"--- 开始执行重命名 (后端), 共 {len(rename_plan)} 项 ---")
 
    # 在实际执行前,检查一遍潜在冲突(新名已存在,且不是本次重命名的旧名)
    existing_targets = set()
    plan_sources = set(old for old, new in rename_plan)
    for old_path, new_path in rename_plan:
         if os.path.exists(new_path) and new_path not in plan_sources:
              existing_targets.add(os.path.basename(new_path))
 
    if existing_targets:
        logging.warning("执行前再次检查到冲突,以下目标已存在,将被跳过:")
        for name in sorted(list(existing_targets)):
             logging.warning(f"- {name}")
 
 
    for old_path, new_path in rename_plan:
        old_name = os.path.basename(old_path)
        new_name = os.path.basename(new_path)
 
        if os.path.exists(new_path):
            logging.warning(f"跳过: 目标 '{new_name}' 已存在。")
            skipped_count += 1
            continue
 
        try:
            os.rename(old_path, new_path)
            logging.info(f"成功: '{old_name}' -> '{new_name}'")
            renamed_count += 1
        except OSError as e:
            logging.error(f"失败: 无法重命名 '{old_name}'。原因: {e}")
            error_count += 1
 
    logging.info(f"--- 重命名执行完毕 (后端) ---")
    logging.info(f"成功: {renamed_count}, 跳过: {skipped_count}, 错误: {error_count}")
    return (renamed_count, skipped_count, error_count)
 
 
# --- 3. 主应用类 (GUI) ---
class BatchFileApp(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title(APP_NAME)
        # 设置一个初始窗口大小 (可选)
        self.geometry("750x650")
 
        # 用于存储当前重命名计划,以便预览后执行
        self.current_rename_plan = []
 
        # 配置日志系统 (不再需要 self.log_filename)
        # self.log_filename = f"batch_tool_gui_log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log" # 已移除
        self.setup_logging()
 
        # 创建主界面
        self.create_widgets()
 
        logging.info(f"--- {APP_NAME} 已启动 ---")
        if not DOCX_ENABLED:
            logging.warning("未找到 'python-docx' 库,无法创建标准 .docx 文件。")
 
    def setup_logging(self):
        log_format = '%(asctime)s - %(levelname)s - %(message)s'
        log_level = logging.INFO
 
        # 获取根 logger
        self.logger = logging.getLogger()
        self.logger.setLevel(log_level)
 
        # 清除可能已存在的处理器
        for handler in self.logger.handlers[:]:
            self.logger.removeHandler(handler)
 
        # 文件处理器 <<<<<<< ******** 已移除 ********
        # file_handler = logging.FileHandler(self.log_filename, encoding='utf-8')
        # file_handler.setFormatter(logging.Formatter(log_format))
        # self.logger.addHandler(file_handler)
 
        # GUI 文本区域处理器 (这个保留)
        self.gui_log_handler = None # 初始化,后面创建控件时再赋值
 
    def create_widgets(self):
        # 创建主框架
        main_frame = ttk.Frame(self, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)
 
        # 创建选项卡控件
        self.notebook = ttk.Notebook(main_frame)
        self.notebook.pack(fill=tk.BOTH, expand=True, pady=(0, 10))
 
        # --- 创建 "生成文件" 选项卡 ---
        self.tab_generate = ttk.Frame(self.notebook, padding="10")
        self.notebook.add(self.tab_generate, text="批量生成文件")
        self.create_generate_tab()
 
        # --- 创建 "重命名文件" 选项卡 ---
        self.tab_rename = ttk.Frame(self.notebook, padding="10")
        self.notebook.add(self.tab_rename, text="批量重命名文件")
        self.create_rename_tab()
 
        # --- 创建日志显示区域 ---
        log_frame = ttk.LabelFrame(main_frame, text="日志和状态", padding="5")
        log_frame.pack(fill=tk.BOTH, expand=True)
 
        self.log_area = scrolledtext.ScrolledText(log_frame, state='disabled', height=15, wrap=tk.WORD, font=("Consolas", 9))
        self.log_area.pack(fill=tk.BOTH, expand=True)
 
        # --- 配置 GUI 日志 Handler ---
        # 确保 log_area 已创建
        if hasattr(self, 'log_area'):
            self.gui_log_handler = TextHandler(self.log_area)
            self.gui_log_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
            self.logger.addHandler(self.gui_log_handler) # 只添加这一个 handler
        else:
             self.logger.error("GUI Log Area 未成功创建,无法添加 TextHandler。")
 
    # --- "生成文件" 选项卡内容 --- (保持不变)
    def create_generate_tab(self):
        frame = self.tab_generate
        row_idx = 0
        ttk.Label(frame, text="目标文件夹:").grid(row=row_idx, column=0, padx=5, pady=5, sticky="w")
        self.gen_folder_var = tk.StringVar(value=os.getcwd())
        self.gen_folder_entry = ttk.Entry(frame, textvariable=self.gen_folder_var, width=60)
        self.gen_folder_entry.grid(row=row_idx, column=1, padx=5, pady=5, sticky="ew")
        ttk.Button(frame, text="浏览...", command=lambda: self.browse_folder(self.gen_folder_var)).grid(row=row_idx, column=2, padx=5, pady=5)
        row_idx += 1
        ttk.Label(frame, text="生成数量:").grid(row=row_idx, column=0, padx=5, pady=5, sticky="w")
        self.gen_count_var = tk.StringVar(value="10")
        self.gen_count_entry = ttk.Entry(frame, textvariable=self.gen_count_var, width=10)
        self.gen_count_entry.grid(row=row_idx, column=1, padx=5, pady=5, sticky="w")
        ttk.Label(frame, text="起始编号:").grid(row=row_idx, column=1, padx=(80, 5), pady=5, sticky="w")
        self.gen_start_var = tk.StringVar(value="1")
        self.gen_start_entry = ttk.Entry(frame, textvariable=self.gen_start_var, width=10)
        self.gen_start_entry.grid(row=row_idx, column=1, padx=(140, 5), pady=5, sticky="w")
        row_idx += 1
        ttk.Label(frame, text="文件前缀 (可选):").grid(row=row_idx, column=0, padx=5, pady=5, sticky="w")
        self.gen_prefix_var = tk.StringVar()
        self.gen_prefix_entry = ttk.Entry(frame, textvariable=self.gen_prefix_var, width=30)
        self.gen_prefix_entry.grid(row=row_idx, column=1, padx=5, pady=5, sticky="w")
        ttk.Label(frame, text="文件后缀 (如 .txt):").grid(row=row_idx, column=1, padx=(230,5), pady=5, sticky="w")
        self.gen_suffix_var = tk.StringVar(value=".docx")
        self.gen_suffix_entry = ttk.Entry(frame, textvariable=self.gen_suffix_var, width=15)
        self.gen_suffix_entry.grid(row=row_idx, column=1, padx=(330,5), pady=5, sticky="w")
        row_idx += 1
        generate_button = ttk.Button(frame, text="开始生成文件", command=self.generate_files_gui)
        generate_button.grid(row=row_idx, column=1, padx=5, pady=15, sticky="e")
        frame.grid_columnconfigure(1, weight=1)
 
    # --- "重命名文件" 选项卡内容 --- (保持不变, 内部顺序已修正)
    def create_rename_tab(self):
        frame = self.tab_rename
        row_idx = 0
        ttk.Label(frame, text="目标文件夹:").grid(row=row_idx, column=0, padx=5, pady=5, sticky="w")
        self.rename_folder_var = tk.StringVar(value=os.getcwd())
        self.rename_folder_entry = ttk.Entry(frame, textvariable=self.rename_folder_var, width=60)
        self.rename_folder_entry.grid(row=row_idx, column=1, columnspan=2, padx=5, pady=5, sticky="ew")
        ttk.Button(frame, text="浏览...", command=lambda: self.browse_folder(self.rename_folder_var)).grid(row=row_idx, column=3, padx=5, pady=5)
        row_idx += 1
        ttk.Label(frame, text="重命名类型:").grid(row=row_idx, column=0, padx=5, pady=10, sticky="w")
        self.rename_type_var = tk.StringVar(value="suffix")
        types_frame = ttk.Frame(frame)
        types_frame.grid(row=row_idx, column=1, columnspan=3, padx=5, pady=5, sticky="w")
        ttk.Radiobutton(types_frame, text="修改后缀名", variable=self.rename_type_var, value="suffix", command=self.update_rename_options).pack(side=tk.LEFT, padx=5)
        ttk.Radiobutton(types_frame, text="修改前缀 (简单替换)", variable=self.rename_type_var, value="prefix_part", command=self.update_rename_options).pack(side=tk.LEFT, padx=5)
        ttk.Radiobutton(types_frame, text="使用正则表达式", variable=self.rename_type_var, value="regex", command=self.update_rename_options).pack(side=tk.LEFT, padx=5)
        row_idx += 1
        self.rename_options_frame = ttk.Frame(frame)
        self.rename_options_frame.grid(row=row_idx, column=0, columnspan=4, padx=5, pady=5, sticky="ew")
        self.rename_options_frame.grid_columnconfigure(1, weight=1)
        self.create_rename_suffix_options()
        self.create_rename_prefix_part_options()
        self.create_rename_regex_options()
        row_idx += 1
        action_frame = ttk.Frame(frame)
        action_frame.grid(row=row_idx, column=0, columnspan=4, padx=5, pady=15, sticky="e")
        self.preview_button = ttk.Button(action_frame, text="预览重命名", command=self.preview_rename_gui)
        self.preview_button.pack(side=tk.LEFT, padx=5)
        self.confirm_button = ttk.Button(action_frame, text="确认重命名", command=self.confirm_rename_gui, state=tk.DISABLED)
        self.confirm_button.pack(side=tk.LEFT, padx=5)
        self.update_rename_options()
        frame.grid_columnconfigure(1, weight=1)
 
    # --- 创建不同重命名类型的选项子框架 --- (保持不变)
    def create_rename_suffix_options(self):
        self.suffix_frame = ttk.Frame(self.rename_options_frame, padding="5")
        ttk.Label(self.suffix_frame, text="旧后缀名 (如 .txt):").grid(row=0, column=0, padx=5, pady=5, sticky="w")
        self.old_suffix_var = tk.StringVar()
        ttk.Entry(self.suffix_frame, textvariable=self.old_suffix_var, width=20).grid(row=0, column=1, padx=5, pady=5, sticky="w")
        ttk.Label(self.suffix_frame, text="新后缀名 (如 .md):").grid(row=1, column=0, padx=5, pady=5, sticky="w")
        self.new_suffix_var = tk.StringVar()
        ttk.Entry(self.suffix_frame, textvariable=self.new_suffix_var, width=20).grid(row=1, column=1, padx=5, pady=5, sticky="w")
 
    def create_rename_prefix_part_options(self):
        self.prefix_part_frame = ttk.Frame(self.rename_options_frame, padding="5")
        ttk.Label(self.prefix_part_frame, text="查找内容:").grid(row=0, column=0, padx=5, pady=5, sticky="w")
        self.old_part_var = tk.StringVar()
        ttk.Entry(self.prefix_part_frame, textvariable=self.old_part_var, width=40).grid(row=0, column=1, padx=5, pady=5, sticky="ew")
        ttk.Label(self.prefix_part_frame, text="替换为:").grid(row=1, column=0, padx=5, pady=5, sticky="w")
        self.new_part_var = tk.StringVar()
        ttk.Entry(self.prefix_part_frame, textvariable=self.new_part_var, width=40).grid(row=1, column=1, padx=5, pady=5, sticky="ew")
        self.prefix_part_frame.grid_columnconfigure(1, weight=1)
 
    def create_rename_regex_options(self):
        self.regex_frame = ttk.Frame(self.rename_options_frame, padding="5")
        ttk.Label(self.regex_frame, text="正则表达式:").grid(row=0, column=0, padx=5, pady=5, sticky="w")
        self.regex_pattern_var = tk.StringVar()
        ttk.Entry(self.regex_frame, textvariable=self.regex_pattern_var, width=50).grid(row=0, column=1, padx=5, pady=5, sticky="ew")
        ttk.Label(self.regex_frame, text="替换字符串:").grid(row=1, column=0, padx=5, pady=5, sticky="w")
        self.regex_replace_var = tk.StringVar()
        ttk.Entry(self.regex_frame, textvariable=self.regex_replace_var, width=50).grid(row=1, column=1, padx=5, pady=5, sticky="ew")
        self.regex_frame.grid_columnconfigure(1, weight=1)
 
    # --- 更新重命名选项的显示 --- (保持不变)
    def update_rename_options(self):
        self.suffix_frame.grid_remove()
        self.prefix_part_frame.grid_remove()
        self.regex_frame.grid_remove()
        if hasattr(self, 'confirm_button'):
             self.confirm_button.config(state=tk.DISABLED)
        self.current_rename_plan = []
        selected_type = self.rename_type_var.get()
        if selected_type == "suffix":
            self.suffix_frame.grid(row=0, column=0, sticky="ew")
        elif selected_type == "prefix_part":
            self.prefix_part_frame.grid(row=0, column=0, sticky="ew")
        elif selected_type == "regex":
            self.regex_frame.grid(row=0, column=0, sticky="ew")
 
    # --- 按钮命令函数 --- (保持不变)
    def browse_folder(self, path_var):
        folder_selected = filedialog.askdirectory()
        if folder_selected:
            path_var.set(folder_selected)
            logging.info(f"已选择文件夹: {folder_selected}")
 
    def generate_files_gui(self):
        folder = self.gen_folder_var.get()
        count_str = self.gen_count_var.get()
        start_str = self.gen_start_var.get()
        prefix = self.gen_prefix_var.get()
        suffix = self.gen_suffix_var.get()
        if not os.path.isdir(folder):
            messagebox.showerror("错误", f"目标文件夹无效或不存在:\n{folder}")
            return
        try:
            count = int(count_str)
            if count <= 0: raise ValueError("数量必须大于0")
        except ValueError as e:
            messagebox.showerror("错误", f"生成数量无效: {e}")
            return
        try:
            start_num = int(start_str)
        except ValueError:
            messagebox.showerror("错误", "起始编号必须是一个整数。")
            return
        if not suffix:
             messagebox.showerror("错误", "文件后缀不能为空。")
             return
        # 不再自动加点
        # if not suffix.startswith('.'):
        #    suffix = '.' + suffix
        #    logging.info(f"后缀自动修正为 '{suffix}'")
 
        confirm_msg = (
            f"将在文件夹:\n{folder}\n\n"
            f"生成 {count} 个文件,从编号 {start_num} 开始。\n"
            f"前缀: '{prefix}' (无前缀则为空)\n"
            f"后缀: '{suffix}'\n\n"
            f"确定要开始吗?"
        )
        if messagebox.askyesno("确认生成操作", confirm_msg):
            logging.info("用户确认生成。")
            try:
                 success_count, skipped_count = backend_create_files(folder, count, start_num, prefix, suffix)
                 messagebox.showinfo("生成完成", f"成功生成 {success_count} 个文件。\n跳过 {skipped_count} 个文件 (已存在或错误)。\n详情请查看日志。")
            except Exception as e:
                 logging.error(f"生成文件时发生未预期错误: {e}")
                 messagebox.showerror("意外错误", f"生成过程中发生错误:\n{e}")
        else:
            logging.info("用户取消了生成操作。")
 
    def preview_rename_gui(self):
        folder = self.rename_folder_var.get()
        rename_type = self.rename_type_var.get()
        params = {}
        self.current_rename_plan = []
        self.confirm_button.config(state=tk.DISABLED)
        if not os.path.isdir(folder):
            messagebox.showerror("错误", f"目标文件夹无效或不存在:\n{folder}")
            return
 
        if rename_type == 'suffix':
            params['old_suffix'] = self.old_suffix_var.get()
            params['new_suffix'] = self.new_suffix_var.get()
            if not params['old_suffix'] or not params['new_suffix']:
                 messagebox.showerror("错误", "新旧后缀名都不能为空。")
                 return
            if not params['old_suffix'].startswith('.'): params['old_suffix'] = '.' + params['old_suffix']
            if not params['new_suffix'].startswith('.'): params['new_suffix'] = '.' + params['new_suffix']
            if params['old_suffix'].lower() == params['new_suffix'].lower():
                 messagebox.showerror("错误", "新旧后缀名不能相同 (忽略大小写)。")
                 return
        elif rename_type == 'prefix_part':
            params['old_part'] = self.old_part_var.get()
            params['new_part'] = self.new_part_var.get()
            if not params['old_part']:
                 messagebox.showerror("错误", "要查找的旧内容不能为空。")
                 return
        elif rename_type == 'regex':
            pattern_str = self.regex_pattern_var.get()
            params['replacement'] = self.regex_replace_var.get()
            if not pattern_str:
                 messagebox.showerror("错误", "正则表达式不能为空。")
                 return
            try:
                 params['pattern'] = re.compile(pattern_str)
            except re.error as e:
                 messagebox.showerror("错误", f"无效的正则表达式:\n{e}")
                 return
        else:
            messagebox.showerror("错误", "未知的重命名类型。")
            return
 
        logging.info("--- 开始预览重命名 ---")
        try:
            self.current_rename_plan = backend_build_rename_plan(folder, rename_type, params)
        except Exception as e:
             logging.error(f"构建重命名计划时发生意外错误: {e}")
             messagebox.showerror("意外错误", f"构建预览时出错:\n{e}")
             return
 
        if self.current_rename_plan is None:
             messagebox.showerror("预览失败", "构建重命名计划时遇到错误,请检查日志。")
             return
        if not self.current_rename_plan:
            logging.info("预览结果:没有找到符合条件可供重命名的文件。")
            messagebox.showinfo("预览结果", "没有找到符合条件的文件进行重命名。")
            return
 
        logging.info("--- 重命名预览 (共 {} 项) ---".format(len(self.current_rename_plan)))
        potential_conflicts = []
        plan_sources = set(old for old, new in self.current_rename_plan)
        for old_path, new_path in self.current_rename_plan:
            old_name = os.path.basename(old_path)
            new_name = os.path.basename(new_path)
            logging.info(f"'{old_name}'  ->  '{new_name}'")
            if os.path.exists(new_path) and new_path not in plan_sources:
                 potential_conflicts.append(new_name)
        if potential_conflicts:
             logging.warning("!!! 潜在冲突警告 (目标已存在,将被跳过): " + ", ".join(sorted(list(set(potential_conflicts)))))
        logging.info("--- 预览结束 ---")
        logging.warning("请仔细检查日志区域的预览!")
        self.confirm_button.config(state=tk.NORMAL)
        messagebox.showinfo("预览生成", f"预览已生成 ({len(self.current_rename_plan)} 项),请在日志区域查看。\n核对无误后可点击 '确认重命名'。")
 
    def confirm_rename_gui(self):
        if not self.current_rename_plan:
            messagebox.showwarning("无法执行", "没有有效的重命名计划可供执行。\n请先点击 '预览重命名' 生成计划。")
            return
        if messagebox.askyesno("确认执行重命名", f"即将根据预览重命名 {len(self.current_rename_plan)} 个文件。\n此操作通常不可逆,确定要继续吗?"):
            logging.info("用户确认执行重命名。")
            try:
                 self.preview_button.config(state=tk.DISABLED)
                 self.confirm_button.config(state=tk.DISABLED)
                 self.update_idletasks()
                 success, skipped, errors = backend_execute_rename(self.current_rename_plan)
                 messagebox.showinfo("重命名完成", f"重命名操作执行完毕。\n成功: {success}, 跳过: {skipped}, 错误: {errors}\n详情请查看日志。")
            except Exception as e:
                 logging.error(f"执行重命名时发生意外错误: {e}")
                 messagebox.showerror("意外错误", f"执行重命名时出错:\n{e}")
            finally:
                 self.current_rename_plan = []
                 self.preview_button.config(state=tk.NORMAL)
                 # 确认按钮保持禁用,直到下一次成功预览
        else:
            logging.info("用户取消了执行重命名操作。")
            self.confirm_button.config(state=tk.NORMAL)
 
 
# --- 4. 启动应用程序 ---
if __name__ == "__main__":
    app = BatchFileApp()
    app.mainloop()
husay 发表于 2025-4-2 12:40
zhengzhenhui945 发表于 2025-4-2 15:15
Tath 发表于 2025-4-2 15:34
下来看看,,支持支持
mist123 发表于 2025-4-7 09:59
感谢分享,非常实用
vipxh 发表于 2025-4-25 07:57
这个很好,实用。
sai609 发表于 2025-5-22 07:42
主要是我写小说时批量生成空白章节文件用的:文字不是连着写的吗?怎么新建txt文档
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-5-25 20:17

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表