2012년 12월 24일 월요일

[Python] 특정 디렉토리(폴더)의 모든 파일 이름 알아내기

이전에는 os.listdir이나 glob 같은걸 써서 재귀호출(recursive call)로 특정 디렉토리 아래의 모든 폴더를 순환하며 파일 이름을 모으는 코드를 만들곤 했었는데, 이는 순전히 무식해서 고생한 거였다. Python의 기본 모듈인 os.walk가 이런 역활을 하도록 이미 구축되어 있었다.

현재 디렉토리 아래의 모든 파일(서브디렉토리 포함) 목록을 얻고자 할 때는 그냥 os.walk('./')를 호출해서 이터레이션 하면서 튜플의 3번째 리스트만 쭈욱 살펴보면 된다.
import os
for root, dirs, files in os.walk('./'):
    for file in files:
        print file
이런 식으로 호출하면 모든 파일 이름이 표시된다.

os.walk는 특정 디렉토리 아래의 모든 디렉토리와 파일의 목록을 얻어 올 수 있도록 도와준다. 이터레이션(for문)에서 3개의 아이템으로 구성된 튜플로 분해가 가능한데 이름만으로도 무엇인지 알 수 있다. root는 어떤 디렉토리인지, dirs는 root 아래의 디렉토리 목록, 그리고 files는 root 아래의 파일 목록이다. 모든 목록은 리스트 형태이다.

필요하다면 디렉토리 목록도 만들 수 있고 파일 목록도 만들 수 있고 정말 활용하기 편하다.

이 모듈을 알고 나니 이전에 했던 삽질이 정말 애처롭다. 역시 모르면 손발이 고생하는데 프로그래머는 모르면 손발과 함께 머리도 고생한다. :-X

좀 더 기능이 많으니 자세한 내용은 공식 os 모듈 문서를 참고하자.

내용이 짧은 것 같아서 한가지 예제 코드를 적어본다. 아래 코드의 allfiles() 함수는 특정 디렉토리 아래의 모든 파일의 절대경로 목록을 리턴하는 함수이다.
import os

def allfiles(path):
    res = []

    for root, dirs, files in os.walk(path):
        rootpath = os.path.join(os.path.abspath(path), root)

        for file in files:
            filepath = os.path.join(rootpath, file)
            res.append(filepath)

    return res
좀 더 기교를 부리면 라인수를 줄일 수 있겠지만 풀어 쓰는게 오히려 이해에는 도움이 되는거 같아서 긴 코드를 나열했다. Python을 잘 안다면 몇 줄을 줄일 수도 있을 것이다.

관련링크: [Python] Directory(Folder) / File 목록 다루기

댓글 3개 :

Unknown :
작성자가 댓글을 삭제했습니다.
아이울 :

이렇게 찾은 파일들을 복사하려면 어떻게 해야할까요?? 예를 들어 어떤 디렉토리 안에 jpg모든 파일을 찾아서 복사를 하고 싶으면 어떻게 코딩 해야 할까요??

import os
import shutil

for root, dirs, files in os.walk('./'):
for file in files:
if file.endswith('.jpg'):
if not os.path.exists ('jpg_files'):
os.mkdir ('jpg_files')

shutil을 어떻게 활용해야 할지 모르겠네요 ㅠㅠ

Seorenn :

복사는 그냥 shutil.copy() 쓰시면 쉽게 될텐데요

shutil.copy(file, "/foo/bar/")

참고로 꼭 파이썬으로 구현할 필요가 없고 유닉스/리눅스/맥 환경이라면 그냥 쉘 커맨드 쓰시는게 더 쉬워요.

$ find . -name "*.jpg" -exec cp {} /foo/bar/ \;

(언급된 모든 코드는 시험해 보지 않았기 때문에 오류가 있을 수 있습니다)