Scripts y automatización de archivos

Combinar archivos CSV y conservar los nombres de origen

Combina en orden archivos CSV con la misma estructura de columnas y añade una columna source_file. Usa conjuntos de datos pequeños para comprobar nombres de elementos con comas, columnas faltantes y salidas ya existentes.

Ver el índice

La traducción se ha realizado con IA. Comprueba el código, las unidades y los valores junto con el original. La revisión por hablantes nativos de cada idioma aún no se ha completado. English

Para quién esPrincipiantes de Python que quieren combinar en una sola tabla archivos CSV de distintas fechas o de diferentes personas.

Preparación
  • Instala Python 3.12 o posterior y comprueba la versión en una terminal con python --version.
  • Extrae el ZIP de ejemplo en una carpeta nueva. No ejecutes el ejemplo desde dentro del archivo ZIP.
  • Abre una terminal en la carpeta que contiene example.py. Si el comando python no está disponible en Windows, usa py. En macOS o Linux, usa python3 si tu entorno lo requiere.
  • No se necesitan paquetes externos ni cuentas. Los archivos incluidos son datos sintéticos creados para este tutorial.

01Combina dos archivos en cinco filas

Si los números parecen incorrectos después de combinar archivos, puede ser difícil rastrear de dónde proceden. Este ejemplo conserva las cuatro columnas originales y añade source_file al final. El objetivo es poder identificar directamente el nombre del archivo original desde cada fila del resultado. Primero, suma las 2 y 3 filas de datos de los archivos de entrada y anota el total esperado de 5.

  1. Busca inputs/sales_01.csv e inputs/sales_02.csv en la carpeta extraída.
  2. Abre ambos archivos en un editor de texto y comprueba que la primera línea sea date,item,quantity,unit_price.
  3. Ejecuta el comando siguiente en una terminal situada en la carpeta que contiene example.py.
  4. Abre outputs/merged.csv y comprueba que haya cinco filas de datos y una columna source_file.
bash
python example.py

Mantener separadas las carpetas de entrada y salida evita que un merged.csv anterior se convierta en un archivo de entrada en una ejecución posterior. El código también localiza inputs en relación con example.py. Si conservas la estructura de carpetas al extraer el ZIP, no necesitas cambiar las rutas.

02Haz coincidir la estructura de columnas antes de combinar

Columna de entradaValor de ejemploCómo lo trata este ejemplo
date2026-09-01Se conserva como texto
item노트Se conserva, incluidas comas y comillas
quantity2Se conserva como texto sin calcular
unit_price2500Se conserva como texto sin calcular

Deben coincidir tanto los nombres de las columnas como su orden. Por ejemplo, el script se detiene si un archivo usa qty en lugar de quantity o coloca unit_price en otra posición. No intenta adivinar significados ni alinear columnas automáticamente, lo que permite detectar cuándo se han mezclado formatos de distintos departamentos.

Los datos sintéticos incluyen “메모지, 대형” (bloc de notas grande) y “표지 "파랑"” (cubierta "azul"), que contiene comillas dobles. Leer un CSV usando simplemente split con comas puede dividir estos valores en campos incorrectos. Deja que el módulo estándar csv gestione las reglas de comillas y vuelve a escribir las filas tal como se leyeron.

03Código completo utilizado en este ejemplo

collect_rows comprueba el encabezado y las filas de cada CSV y añade el nombre del archivo original. Solo después de que todas las comprobaciones se superen, main crea una salida nueva. Este orden evita que quede una combinación parcial de los primeros archivos cuando un archivo posterior tiene columnas incorrectas.

example.py
"""inputs의 같은 구조 CSV를 결합합니다. 각 행에 원본 파일명을 붙입니다."""

import csv
import sys
from pathlib import Path

BASE = Path(__file__).resolve().parent
INPUT = BASE / "inputs"
OUTPUT = BASE / "outputs"
FIELDS = ["date", "item", "quantity", "unit_price"]


def collect_rows():
    if INPUT.is_symlink() or not INPUT.is_dir():
        raise ValueError("inputs 폴더가 없거나 링크입니다.")
    if getattr(INPUT, "is_junction", lambda: False)():
        raise ValueError("연결 디렉터리는 처리하지 않습니다.")
    # inputs 바로 아래의 .csv 파일만 읽습니다. 순서를 명시해 결과를 재현합니다.
    paths = sorted(
        (p for p in INPUT.iterdir() if p.suffix.lower() == ".csv"),
        key=lambda p: p.name.casefold(),
    )
    if not paths:
        raise ValueError("inputs에 CSV 파일이 없습니다.")
    merged = []
    counts = []
    for path in paths:
        if path.is_symlink() or not path.is_file():
            raise ValueError(f"일반 CSV 파일이 아닙니다: {path.name}")
        with path.open("r", encoding="utf-8-sig", newline="") as stream:
            reader = csv.DictReader(stream, strict=True)
            if reader.fieldnames != FIELDS:
                raise ValueError(f"{path.name}: 열 이름과 순서는 {FIELDS}여야 합니다.")
            count = 0
            for row in reader:
                # 열이 많으면 None 키, 적으면 None 값이 생깁니다.
                if None in row or any(value is None or not value.strip() for value in row.values()):
                    raise ValueError(f"{path.name}, {reader.line_num}행: 열 수 또는 빈 값을 확인하세요.")
                merged.append({**row, "source_file": path.name})
                count += 1
            counts.append((path.name, count))
    return merged, counts


def main():
    if OUTPUT.exists() or OUTPUT.is_symlink():
        raise FileExistsError("outputs가 이미 있습니다. 기존 결과를 옮긴 뒤 실행하세요.")
    rows, counts = collect_rows()  # 모든 파일을 검증한 다음에 출력합니다.
    OUTPUT.mkdir()
    target = OUTPUT / "merged.csv"
    with target.open("x", encoding="utf-8-sig", newline="") as stream:
        writer = csv.DictWriter(stream, fieldnames=FIELDS + ["source_file"])
        writer.writeheader()
        writer.writerows(rows)
    for name, count in counts:
        print(f"{name}: {count}행")
    print(f"완료: {len(counts)}개 파일 → {len(rows)}행")
    print(target)
    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)

Las comprobaciones aprovechan que DictReader añade una clave None cuando hay demasiados campos de datos y un valor None cuando hay demasiado pocos. También se rechazan las cadenas vacías y los valores formados solo por espacios. Configurar newline como cadena vacía y especificar una codificación compatible con BOM de UTF-8 mantiene coherente el tratamiento de saltos de línea y texto coreano.

04Compara tanto el número de filas como los archivos de origen

Orden de fila del resultadoitemquantitysource_file
1노트2sales_01.csv
2펜3sales_01.csv
3노트1sales_02.csv
4메모지, 대형4sales_02.csv
5표지 "파랑"1sales_02.csv

La terminal muestra “sales_01.csv: 2행” (dos filas), “sales_02.csv: 3행” (tres filas) y “완료: 2개 파일 → 5행” (completado: dos archivos → cinco filas), en ese orden. El encabezado de la primera línea no se cuenta como dato. Ver 노트 (cuaderno) dos veces no es un error. Se conservan ambas filas originales; no se han calculado totales ni eliminado duplicados.

05Haz cuatro comprobaciones antes de confiar en el resultado

  1. Comprueba que la suma de las filas de entrada, 5, coincida con el número de filas de datos del resultado.
  2. Comprueba que dos filas tengan source_file igual a sales_01.csv y tres tengan sales_02.csv.
  3. Comprueba que el nombre de item que contiene una coma permanezca en una sola celda y que las comillas dobles no hayan desaparecido.
  4. Vuelve a abrir los dos archivos originales y confirma que su contenido no ha cambiado. Comprueba también que volver a ejecutar el script se detenga porque outputs ya existe.

En trabajo real, comprobar el número de filas es distinto de comprobar los totales. Aunque los totales monetarios coincidan por casualidad, podría faltar una fila y existir otra duplicada. Como este paso no realiza cálculos, empieza comparando el número de filas por origen y el texto original.

06Practica añadiendo un tercer archivo

Antes de volver a ejecutar, cambia el nombre de la primera carpeta outputs para conservarla. Añade sales_03.csv dentro de inputs con el mismo encabezado y una fila de datos. El recuento esperado de datos es seis. Comprueba que la nueva fila tenga sales_03.csv en source_file para ver cómo añadir una entrada afecta a la columna de trazabilidad.

Solo se incluyen archivos con extensión .csv situados directamente dentro de inputs. El script no busca recursivamente en subcarpetas ni combina notas de texto o libros de Excel. Si no encuentra archivos CSV, lo interpreta como una selección incorrecta de entrada y se detiene. Un CSV válido que solo tenga encabezado cuenta como 0 filas y no impide combinar los demás archivos.

07Revisa los errores en lugar de aceptar resultados parciales

Motivo de la detenciónDónde comprobarCómo corregirlo
Los nombres o el orden de las columnas no coincidenLa primera línea del archivo indicadoHaz coincidir exactamente las cuatro columnas obligatorias.
Número de campos incorrecto o valor vacíoEl nombre del archivo y el número de línea indicadoComprueba campos faltantes, delimitadores adicionales y valores vacíos.
Error de comillas CSVUna comilla doble sin cerrarUsa una copia cuya estructura se haya reparado en un editor CSV.
Error de codificaciónLa codificación con la que se guardó el archivo de entradaCrea una copia exportada en UTF-8.
outputs already existsLa carpeta de resultados anteriorMueve los resultados y vuelve a ejecutar.

Los números de línea de los errores se refieren a las líneas físicas leídas del CSV. En archivos CSV complejos con saltos de línea dentro de valores entre comillas, pueden diferir de los números de filas de datos de una hoja de cálculo. Usa primero el nombre del archivo indicado en el mensaje para localizar el origen.

08Dónde termina la combinación y empieza la validación de datos

Este script comprueba la estructura de columnas, los valores vacíos y la sintaxis CSV. No determina si quantity es numérico, si date es una fecha válida o si los importes cumplen las reglas de trabajo. Si necesitas cálculos después de una combinación sencilla, añade la conversión numérica y las comprobaciones de rangos permitidos como pasos de validación separados.

Todas las filas se recopilan en memoria y se guardan después de la validación, por lo que este ejemplo es adecuado para practicar con archivos de trabajo pequeños. Los CSV muy grandes requieren un diseño con salida temporal y procesamiento por etapas. Un error de disco durante el guardado puede dejar resultados parciales; no consideres la ejecución correcta si no aparece un mensaje de finalización. Los cambios simultáneos en los archivos de entrada y los fallos de rutas de red quedan fuera del alcance de esta verificación.

Registro de ejecución y verificación

2026-09-19 · Windows 11 · CPython 3.12.14 · Sin paquetes adicionales · Ejecutado en una copia temporal de la distribución

  • Se combinaron 2 archivos CSV en 5 filas y se comprobaron los recuentos de source_file
  • Se conservaron las celdas que contienen comas y comillas dobles
  • Se rechazaron encabezados incorrectos, campos faltantes o adicionales, valores vacíos y comillas mal formadas antes de crear la salida
  • Se comprobó el tratamiento de archivos CSV solo con encabezado y de la ausencia de archivos CSV
  • Se confirmó que los hashes SHA-256 de los originales no cambiaron y que se conservaba la salida existente
Límites de la verificación
  • No se midió el uso de memoria con archivos grandes.
  • No se valida el significado de negocio de los números y las fechas.
  • La ejecución se verificó en Windows.

Criterios de redacción y verificación de todo el sitio

Archivos de ejemplo para ejecutar

Incluye código, datos de entrada e instrucciones de ejecución. Extrae el ZIP y lee primero README.txt.

Descargar ZIP de ejemplo

El código de ejemplo, los nombres de archivo y las claves de entrada se mantienen como en el original. Consulta también los comandos y los pasos de comprobación del texto traducido.

Material de práctica original · Guarda los archivos originales por separado antes de ejecutarlo.

Fuentes de referencia

Las explicaciones y los ejemplos son de elaboración propia. Puedes consultar los comportamientos y conceptos relacionados en las siguientes fuentes oficiales.