기본 콘텐츠로 건너뛰기

추천 가젯

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

모바일 청첩장 시리즈 1편 · 기획/스택/배포 리액트 + 비트(Vite)로 모바일 청첩장 만들기 — 1편 안녕하세요, 이번에 결혼 준비를 하면서 여자친구와 같이 모바일 청첩장 을 만들고 있어요. 여자친구가 디자인을 해서 전달해주면 제가 개발을 진행하고 있어요. 이 글은 구현기 1편 으로, 전체 흐름과 스택, 배포 구성까지 “부담 없이” 훑어봅니다. (코드는 여러 버전 테스트 중!) 이 글에서 보는 것 왜 SPA 모바일 청첩장인가? 기본 스택 & 폴더 구조 라우팅 선택: HashRouter가 편한 이유 Cloudflare Pages로 자동 배포 현재 진행 중인 UI 버전들(테스트 기록) 1) 왜 SPA 모바일 청첩장인가? 모바일 청첩장은 핵심이 명확해요. 가볍고 빠르고 끊김이 없어야 하고, 사진/지도/일정이 터치에 친화적 이어야 합니다. 그래서 React + Vite 로 싱글 페이지 앱(SPA)을 구성했고, 정적 호스팅(CDN)인 Cloudflare Pages 에 올려 GitHub 푸시 → 자동 배포 까지 한 번에 묶었습니다. UX 팁 · 이미지 WebP, loading="lazy" 기본 · 큰 터치 타깃 · BGM은 “사용자 탭 후” 재생(모바일 정책) 2) 기본 스택 & 폴더 구조 서버는 따로 두지 않았고, 정적 빌드 결과물( dist/ )만 올립니다. 현재 의존성은 아래와 같아요. package.json(요약) { "name": ...

파이썬 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