Scripts e automação de arquivos

Visualize previamente um lote de alterações de nomes antes de aplicá-las

Compare nomes antigos e novos em uma tabela e verifique conflitos. Apenas um --apply explícito cria cópias em uma nova pasta, mantendo os originais.

Ver o sumário

A tradução foi feita com IA. Confira o código, as unidades e os valores junto com o original. A revisão por falantes nativos de cada idioma ainda não foi concluída. English

Para quem éIniciantes que querem renomear vários arquivos, mas têm receio de regras incorretas ou de sobrescrever arquivos

Preparação
  • Instale Python 3.12 ou posterior e verifique a versão em um terminal com python --version.
  • Extraia o ZIP de exemplo em uma nova pasta. Não execute o exemplo de dentro do arquivo ZIP.
  • Abra um terminal na pasta que contém example.py. Se o comando python não estiver disponível no Windows, use py. No macOS ou Linux, use python3 se seu ambiente exigir.
  • Nenhum pacote externo ou conta é necessário. Os arquivos incluídos são dados sintéticos criados para este tutorial.

01Comece visualizando apenas três nomes

Em uma batch operation, impedir que uma rule incorreta seja aplicada a todos os files é mais importante do que encontrar um typo em um único file. Este exemplo valida toda a name list antes de mostrar o plan. O default command não copia files nem cria folders. Depois de verificar o plan, execute a operação separadamente com --apply.

  1. Na pasta extraída, verifique mapping.csv e os três original files dentro de source_files.
  2. Compare old_name e new_name em mapping.csv. A column da esquerda é o filename atual; a da direita é o name da nova copy.
  3. Execute o default command abaixo e verifique se os três pares de names ligados por setas são os que você pretendia.
  4. Nesta etapa, verifique se source_files permanece inalterado e se outputs ainda não existe.
bash
python example.py

02Leia o mapping de nomes de arquivos

old_namenew_name
메모 초안.txtnote-draft.txt
견적 1.txtquote-001.txt
사진 설명.txtphoto-notes.txt

Cada mapping row conecta um original a um result. Insira old_name exatamente como o filename real aparece, incluindo letter case. Toda a operação para se você omitir um original ou adicionar um name que não existe. Essa rule detecta erros como usar um mapping antigo depois que um novo file foi adicionado à pasta.

Values em new_name são tratados como conflitantes mesmo quando diferem apenas em letter case. Isso impede que report.txt e REPORT.txt se tornem results separados. Leading or trailing spaces, trailing dots, path separators e Windows reserved names também são rejeitados. Uma pessoa deve fazer a verificação final na preview para confirmar que as naming rules são adequadas à tarefa.

03Código completo usado neste exemplo

make_plan verifica todos os inputs e conflicts. main imprime o validated plan e depois verifica se --apply foi fornecido. Mesmo ao aplicar o plan, ele copia file contents com new names em vez de usar rename nos originals, portanto você ainda pode inspecionar o starting state.

example.py
"""기본은 미리보기입니다. --apply일 때만 새 이름의 복사본을 만듭니다."""

import argparse
import csv
import re
import shutil
import sys
from pathlib import Path

BASE = Path(__file__).resolve().parent
INPUT = BASE / "source_files"
MAPPING = BASE / "mapping.csv"
OUTPUT = BASE / "outputs"
RESERVED = {"CON", "PRN", "AUX", "NUL"} | {
    f"{prefix}{number}" for prefix in ("COM", "LPT") for number in range(1, 10)
}


def validate_name(name):
    # 폴더 경로, Windows 예약 이름, 제어 문자 등을 이름으로 받지 않습니다.
    if (not name or name in {".", ".."} or name != name.strip()
            or name.endswith(".") or re.search(r'[<>:"/\\|?*\x00-\x1f]', name)
            or name.split(".")[0].upper() in RESERVED):
        raise ValueError(f"사용할 수 없는 파일명: {name!r}")


def make_plan():
    if (INPUT.is_symlink() or not INPUT.is_dir()
            or getattr(INPUT, "is_junction", lambda: False)()):
        raise ValueError("source_files는 실제 폴더여야 합니다.")
    if MAPPING.is_symlink():
        raise ValueError("mapping.csv 링크는 처리하지 않습니다.")
    sources = list(INPUT.iterdir())
    if any(path.is_symlink() or not path.is_file() for path in sources):
        raise ValueError("source_files에는 일반 파일만 넣으세요.")
    if not sources:
        raise ValueError("source_files에 파일이 없습니다.")
    plan, old_keys, new_keys = [], set(), set()
    with MAPPING.open("r", encoding="utf-8-sig", newline="") as stream:
        reader = csv.DictReader(stream, strict=True)
        if reader.fieldnames != ["old_name", "new_name"]:
            raise ValueError("mapping.csv의 열은 old_name,new_name이어야 합니다.")
        for row in reader:
            if None in row or any(value is None for value in row.values()):
                raise ValueError(f"mapping.csv {reader.line_num}행의 열 수를 확인하세요.")
            old, new = row["old_name"], row["new_name"]
            validate_name(old)
            validate_name(new)
            if old.casefold() in old_keys:
                raise ValueError(f"원본이 중복 지정되었습니다: {old}")
            if new.casefold() in new_keys:
                raise ValueError(f"새 이름 충돌: {new}")
            old_keys.add(old.casefold())
            new_keys.add(new.casefold())
            plan.append((old, new))
    # 한 파일이라도 누락되거나 없는 파일을 지정하면 아무것도 복사하지 않습니다.
    if {old for old, _ in plan} != {path.name for path in sources}:
        raise ValueError("mapping.csv의 old_name은 원본 파일 전체와 정확히 일치해야 합니다.")
    if OUTPUT.exists() or OUTPUT.is_symlink():
        raise FileExistsError("outputs가 이미 있습니다. 기존 결과를 옮긴 뒤 실행하세요.")
    return plan


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--apply", action="store_true", help="새 이름의 복사본을 outputs/renamed에 만듭니다.")
    args = parser.parse_args()
    plan = make_plan()  # 충돌 검사는 출력 폴더를 만들기 전에 전체에 대해 끝냅니다.
    for old, new in plan:
        print(f"{old} → {new}")
    if not args.apply:
        print(f"미리보기: {len(plan)}개. 파일은 변경되지 않았습니다.")
        print("이름을 확인한 뒤 python example.py --apply 를 실행하세요.")
        return 0

    OUTPUT.mkdir()
    renamed = OUTPUT / "renamed"
    renamed.mkdir()
    for old, new in plan:
        # 이름 변경 대신 복사합니다. xb는 대상이 생겼으면 덮어쓰지 않고 실패합니다.
        with (INPUT / old).open("rb") as source, (renamed / new).open("xb") as target:
            shutil.copyfileobj(source, target)
    with (OUTPUT / "manifest.csv").open("x", encoding="utf-8-sig", newline="") as stream:
        writer = csv.writer(stream)
        writer.writerow(["old_name", "new_name"])
        writer.writerows(plan)
    print(f"완료: {len(plan)}개 복사본 → {renamed}")
    return 0


if __name__ == "__main__":
    try:
        raise SystemExit(main())
    except (OSError, ValueError, csv.Error) as error:
        print(f"중지: {error}", file=sys.stderr)
        raise SystemExit(2)

A opção store_true em argparse torna preview o padrão quando --apply é omitido. Copy destinations são abertos em modo xb para evitar sobrescrever um file que já existe. O mapping concluído também é registrado em manifest.csv para que você possa rastrear um new name até seu original name.

04Crie cópias a partir do plano verificado

Depois de verificar as três preview lines, execute o comando a seguir na mesma pasta. Se você editou mapping.csv após a preview, execute novamente o default command para verificar o novo plan. O apply command não se lembra da preview anterior; ele relê e valida o mapping no momento da execução.

bash
python example.py --apply
LocationResultado esperado
source_files/3 original files mantidos com seus nomes atuais
outputs/renamed/note-draft.txt, quote-001.txt, photo-notes.txt
outputs/manifest.csv3 rows de mapping original → new name após o header

O terminal exibe “완료: 3개 Copy본” (complete: three copies) e o caminho da output folder. Abra cada new file para verificar seu content, além do name. Por exemplo, o practice document number em note-draft.txt deve corresponder ao number em 메모 초안.txt.

05Crie um conflito para verificar se o script para

  1. Extraia outra cópia em uma nova pasta. Não misture error tests com uma pasta que já contém results.
  2. Em mapping.csv, altere o segundo new_name para note-draft.txt, igual ao primeiro, e salve.
  3. Execute python example.py --apply. A mensagem “새 이름 충돌” (new-name collision) deve aparecer.
  4. Verifique se nenhuma pasta outputs foi criada e se os três originals continuam em source_files.
  5. Restaure os mapping values originais e verifique novamente a partir da etapa de preview.

Se a validation ocorresse file por file dentro do copy loop, o primeiro file poderia ser processado antes de o segundo causar um failure. Este exemplo verifica primeiro todos os names para que esses pre-check errors não causem partial application. Ele também para antes de começar se outputs já existir.

06Use suas próprias regras de nomes de documentos

Comece com uma pequena copy de uma única folder ao aplicar isso ao seu trabalho. Coloque copies dos originals em source_files e escreva uma row por file em mapping.csv. Use o full name, incluindo a extension. Uma extension não converte o file format, portanto não mapeie um text file para um name terminado em .pdf.

Se você adicionar numbers, use uma quantidade fixa de dígitos, como 001 e 002, e use um date order consistente para facilitar a localização dos results. Primeiro defina quais fields pertencem ao name, depois verifique sua ordem e qualquer omission na preview. Este exemplo não extrai titles de document contents nem infere sua intent para gerar names automaticamente.

07O que verificar para cada mensagem de parada

MessageO que verificarSolução
New-name collision (새 이름 충돌)Values new_name idênticos ou que diferem apenas em letter caseEscolha final names distintos.
Original specified more than onceold_name repetido em duas rowsMantenha uma row por original.
Must match the complete set of original filesUm missing file ou typo em old_nameCompare novamente o conteúdo da folder com o mapping.
Invalid filenamePaths, reserved names, forbidden characters ou trailing dotsInsira apenas o filename e remova restricted characters.
outputs already existsResults de uma copy operation anteriorRenomeie a result folder para mantê-la e depois comece novamente.

Repetir o mesmo command após aplicar um plan não atualiza existing results. Até a preview para se encontrar uma pasta outputs existente. Essa rule impede que results de operações separadas sejam misturados. Nenhuma overwrite option é fornecida.

08Limites da cópia e verificações que ainda são necessárias

Este exemplo apenas lê os original files e dá new names às copies. Manter tanto os originals quanto suas copies exige storage adicional. Ele preserva document contents, mas não é uma ferramenta para duplicar creation and modification times, access permissions ou todo operating-system metadata.

Errors encontrados antes da cópia, como name conflicts, fazem toda a operação parar. Depois que copying começa, um power failure ou insufficient disk space não é revertido como uma single transaction. Alguns files podem permanecer em outputs, portanto verifique o completion message e todos os três files. Concurrent changes nos originals ou no mapping por outro programa também exigem um design separado.

Registro de execução e verificação

2026-09-19 · Windows 11 · CPython 3.12.14 · Sem pacotes adicionais · Executado em uma temporary copy da distribuição

  • A default preview não cria nenhuma output folder
  • As 3 copies feitas com --apply são byte-for-byte idênticas aos originals
  • Conflicts por identical-name e case-only são rejeitados antes da criação de output
  • Duplicate ou omitted originals, nonexistent originals, path traversal e reserved names são rejeitados
  • Uma execução repetida para preservando os existing results
Limites da verificação
  • Os original files não são renomeados.
  • Partial output não é revertido automaticamente após um disk error.
  • Nem todo file metadata é preservado.
  • A execução foi verificada no Windows.

Princípios de redação e verificação de todo o site

Arquivos de exemplo para executar

Inclui código, dados de entrada e instruções de execução. Extraia o ZIP e leia primeiro o README.txt.

Baixar ZIP de exemplo

O código de exemplo, os nomes de arquivos e as chaves de entrada são mantidos como no original. Consulte também os comandos e os procedimentos de conferência do texto traduzido.

Material de prática original · Guarde os arquivos originais separadamente antes de executar.

Fontes de referência

As explicações e os exemplos são de elaboração própria. Os comportamentos e conceitos relacionados podem ser consultados nas fontes oficiais abaixo.