기본 콘텐츠로 건너뛰기

추천 가젯

리액트 + 비트(Vite)로 모바일 청첩장 만들기 — 2편

모바일 청첩장 시리즈 2편 · R2 갤러리 & Firebase 방명록 Cloudflare R2 · Functions Firebase Firestore 클라우드플레어 R2로 갤러리 저장하고, Firebase로 방명록 달기 안녕하세요, 병민입니다 🙌 1편에서 전체 흐름을 잡았고, 이번엔 사진 업로드/보관 과 방명록 을 연결합니다. 서버는 따로 없고 Cloudflare Pages 를 쓰고 있으니, Pages Functions (= 워커)로 R2에 사전서명 URL을 만들어주고, 프론트에서 그 URL로 바로 업로드하는 구조예요. 방명록은 Firebase DB로 간단·안전하게! 전체 그림 프론트(React) → /api/r2/upload 로 업로드용 URL 요청 → R2에 파일 PUT 프론트(React) → /api/r2/list 로 목록 요청 → 갤러리 렌더 프론트(React) → Firebase SDK로 방명록 작성/조회 1) R2 버킷 & Pages Functions 준비 Cloudflare 대시보드 > R2 > Create bucket (예: wedding-gallery ) 버킷 > Settings > CORS 에서 사이트 도메인 허용(예: https://*.pages.dev , 커스텀 도메인) Pages 프로젝트 > Settings > Functions 에서 R2 바인딩 추가: ...

파이썬 pathlib 완전 정복 🧭 — 파일·디렉터리 경로를 우아하게 다루기

파이썬 pathlib 완전 정복 🧭 — 파일·디렉터리 경로를 우아하게 다루기 pathlib 아이콘

파이썬 pathlib 완전 정복 🧭

더 이상 os.path.join에 문자열 난무는 그만! pathlib.Path객체지향 경로 API로 읽기/쓰기, 탐색, 이동/삭제를 깔끔하고 안전하게 처리합니다.

1) Path 생성과 결합

from pathlib import Path

p = Path("data") / "images" / "cat.png"  # '/' 연산자로 결합
print(p)         # OS별 구분자로 출력
print(p.exists(), p.is_file(), p.is_dir())

home = Path.home()
cwd  = Path.cwd()
print(home, cwd)

2) 파일 읽기/쓰기

from pathlib import Path

txt = Path("notes.txt")
txt.write_text("안녕하세요\npathlib 예제입니다.", encoding="utf-8")  # 생성+쓰기
print(txt.read_text(encoding="utf-8"))                                 # 읽기

binf = Path("logo.png")
data = binf.read_bytes()  # 바이너리 읽기
Path("copy.png").write_bytes(data)  # 바이너리 쓰기
대용량 파일은 open()으로 스트리밍하며 처리하세요.

3) 탐색: iterdir, glob, rglob

from pathlib import Path

root = Path("src")

# 1) 1단계 하위만
for child in root.iterdir():
    print(child)

# 2) 패턴 매칭
for py in root.glob("*.py"):       # 바로 아래에서만
    print(py)

# 3) 재귀 탐색
for py in root.rglob("*.py"):      # 하위 전체
    print(py)

4) 경로 속성과 변형

from pathlib import Path

p = Path("archive/2025/report.csv")
print(p.name)        # 'report.csv'
print(p.stem)        # 'report'
print(p.suffix)      # '.csv'
print(p.suffixes)    # ['.csv']
print(p.parent)      # 'archive/2025'
print(p.parts)       # ('archive','2025','report.csv')

# 이름/확장자 교체
print(p.with_name("summary.csv"))
print(p.with_suffix(".parquet"))

# 절대/해결
print(p.resolve())   # 심볼릭 링크·상대경로 해소
# print(p.relative_to("archive"))  # '2025/report.csv'

5) 파일·디렉터리 조작

from pathlib import Path

# 디렉터리 만들기
out = Path("output/reports")
out.mkdir(parents=True, exist_ok=True)

# 이동/이름변경
src = Path("temp/data.csv")
dst = Path("output/data.csv")
src.replace(dst)  # 같은 디스크면 거의 'mv'

# 안전 삭제
trash = Path("output/old.csv")
if trash.exists():
    trash.unlink()   # 파일만 삭제 (디렉터리는 rmdir)
# 디렉터리 전체 삭제는 shutil.rmtree(out) 사용
주의: unlink()는 파일만 삭제합니다. 디렉터리는 rmdir() 또는 shutil.rmtree()를 사용하세요.

6) 실전 레시피

6-1. 다운로드 폴더를 확장자별로 정리

from pathlib import Path

dl = Path.home() / "Downloads"
for f in dl.iterdir():
    if f.is_file():
        target = dl / f.suffix.lstrip(".").lower()
        target.mkdir(exist_ok=True)
        f.replace(target / f.name)

6-2. 프로젝트 전체 파이썬 파일 수와 총 크기

from pathlib import Path

root = Path(".")
files = list(root.rglob("*.py"))
total_size = sum(f.stat().st_size for f in files)
print(len(files), "files,", total_size, "bytes")

6-3. 날짜 prefix로 일괄 리네임

from pathlib import Path
from datetime import date

albums = Path("photos/album1")
prefix = date.today().strftime("%Y%m%d") + "_"

for f in albums.glob("*.jpg"):
    f.replace(f.with_name(prefix + f.name))

7) 크로스플랫폼 팁

  • 경로 결합은 항상 / 연산자로: Path("a") / "b"
  • 문자열로 출력이 필요하면 str(p) 또는 p.as_posix()
  • Windows 예약 이름/NFC 정규화 등 특수 케이스는 OS별 차이가 있으니 테스트 권장
  • PurePath 계열은 파일 시스템 접근 없이 경로 계산만 할 때 사용

요약

  • pathlib.Path 하나로 경로 조작·입출력·탐색을 객체지향적으로 처리
  • glob/rglob으로 쉽고 빠른 패턴 탐색
  • with_suffix/with_name/replace로 안전한 이름 변경·이동
  • 크로스플랫폼 이식성과 가독성 ↑

자주 묻는 질문(FAQ)

Q1. 문자열만 쓰던 코드와 함께 쓸 수 있나요?
A. 대부분의 표준 라이브러리가 Path를 직접 받거나 자동 변환합니다. 필요하면 str(Path(...))를 넘기세요.

Q2. 디렉터리 비우기/재귀 삭제는 어떻게 하나요?
A. pathlib 자체는 제공하지 않으므로 shutil.rmtree(Path(...))를 사용하세요.

Q3. 파일 잠금/동시성 제어가 필요한데요?
A. 플랫폼별 잠금은 별도 라이브러리를 사용하세요(filelock 등). pathlib는 경로 API에 집중합니다.

댓글

가장 많이 본 글

Icons by Flaticon