Python : pathlib (OS 상관없이 호환되는 filepath 생성하기. Mac/Linux/Windows OS file path. 경로 분석. directory functinos. 파일 읽기. 파일 쓰기. file read. file write)
어떤 폴더나 파일의 경로를 나타낼 때 보통 우리는 아래와 같은 표현 방식을 사용합니다.
my_program/tester/Code/test_program.py
근데 위 표현식은 OS에 따라 에러를 일으킬 수 있습니다.
Mac/Linux에서는 폴더, 파일 구분자로서 슬래쉬(Slash, /)를 사용하지만,
Windows에서는 폴더, 파일 구분자로서 역슬래쉬(Backward slash, \)를 사용하기 때문입니다.
Mac/Linux = my_program/tester/Code/test_program.py
Windows = my_program\tester\Code\test_program.py
혼자서 프로그래밍을 한다면 또는 그렇게 규모가 크지 않은 협업을 한다면 위 차이가 전혀 상관없을 수 있습니다.
저 또한 Mac을 사용하며 개발을 할 때 그냥 위 file path string을 자주 사용하곤 합니다.
근데 어느정도 규모가 커지거나 다양한 OS를 넘나들어야 하는 상황이라면 위 차이는 꽤 거슬리는 문제가 될 수 있습니다.
이럴 때 사용할 수 있는 것이 바로 pathlib 라이브러리 입니다.
pathlib는 built-in module로서 별도로 pip install을 이용하여 설치할 필요가 없습니다.
my_program/tester/Code/test_program.py
위 경로를 pathlib 모듈을 이용해서 나타내면 아래와 같습니다.
import pathlib
# my_program/tester/Code/test_program.py
dir_path = pathlib.Path('my_program') / 'tester' / 'Code' / 'test_program.py'
print(dir_path)
-- Result
my_program/tester/Code/test_program.py
pathlib 모듈은 file path를 나타내는 string을 단순 string이 아닌 객체처럼 취급합니다.
사용법은 위와 같으며,
dir_path = pathlib.Path('my_program') / 'tester' / 'Code' / 'test_program.py'
pathlib.Path class에 가장 상단의 directory를 두고 그 이하로 slash(/)를 이용하여 직관적으로 path를 명시해줍니다.
위 코드는 현재 코드를 실행하는 OS의 종류와는 상관없이 모두 실행됩니다.
기존에는 위같은 작동 방식을 os module을 이용해서 진행했었습니다.
import os
dir_path = os.path.join('my_program', 'tester', 'Code', 'test_program.py')
print(dir_path)
-- Result
my_program/tester/Code/test_program.py
위처럼 os.path.join() method를 이용해도 동일한 결과를 얻을 수 있습니다.
그러면 pathlib 모듈을 이용했을 때에는 고전적으로 계속 이용하던 my_program/tester/Code/test_program.py 같은 형식의 directory string은 사용할 수 없을까요?
아뇨 사용 가능합니다.
import pathlib
dir_path = pathlib.Path('my_program/tester/Code/test_program.py')
print(dir_path)
-- Result
my_program/tester/Code/test_program.py
위 예시를 보면 그냥 Path class의 parameter로서 full directory string을 전달해도 정상적으로 인식하긴 합니다.
pathlib 모듈은 단순히 path를 객체로 만드는 것 뿐 아니라 이를 이용한 다양한 기능을 가집니다.
그 기능 몇가지에 대해 알아봅시다.
1. 파일 읽기
pathlib 모듈을 이용하면 특정 파일에 적힌 텍스트를 읽을 수 있습니다.
마치 open을 사용하는 것 처럼요.
project_test
├── main.py
└── inputs
└── text_files
└── text_contents.txt
현재 디렉토리 구조는 위와 같습니다.
제가 코드를 실행할 파일은 main.py입니다.
import pathlib
dir_path = pathlib.Path('inputs') / 'text_files' / 'test_contents.txt'
print(dir_path, '\n')
file_contents = dir_path.read_text()
print(file_contents)
-- Result
inputs/text_files/test_contents.txt
This is test contents.txt
This file contains test contents that will be read using pathlib module.
1
2
3
4
5
위 예시는 inputs/text_files/test_contents.txt의 내용을 읽는 것입니다.
dir_path = pathlib.Path('inputs') / 'text_files' / 'test_contents.txt'
내용을 읽어들이기 위해 test_contents.txt 파일이 있는 경로를 main.py 기준 상대경로로 지정해줍니다.
여기서 dir_path를 print하면 inputs/text_files/test_contents.txt 처럼 print될 것입니다.
근데 이건 단순히 string이 아니라 경로 객체입니다.
file_contents = dir_path.read_text()
그래서 이렇게 dir_path에 read_text() method를 사용하면 dir_path에 명시된 파일에 담겨있는 텍스트를 읽어옵니다.
2. 파일 쓰기
파일 읽기가 되면 파일 쓰기도 될 것 같지 않나요.
파일 쓰기도 당연히 됩니다.
import pathlib
dir_path = pathlib.Path('inputs') / 'text_files' / 'test_contents_2.txt'
file_contents = dir_path.write_text('''
This is new file created by using pathlib module.
6
7
8
9
10
.
''')
위 예시처럼 write_text() method를 사용하면 파일을 생성할 수 있습니다.
생성되는 파일의 내용은 write_text() method의 parameter로서 전달하면 됩니다.
위 코드를 실행하면 아래처럼 dir_path에 명시한 경로에 text_contents_2.txt 라는 새로운 파일이 하나 생성된 것을 볼 수 있을 것입니다.
project_test
├── main.py
└── inputs
└── text_files
├── text_contents.txt
└── text_contents_2.txt
3. 현재 경로 파악 (cwd)
Mac terminal에서 cwd (current working directory) 명령어는 현재 디렉토리 위치를 나타내줍니다.
pathlib 또한 cwd 기능을 가지고 있습니다.
import pathlib
current_path = pathlib.Path.cwd()
print(current_path)
-- Result
/Users/Documents/code/project_test
위 예시를 보면 현재 파일이 있는 곳의 상위 directory를 나타내줍니다.
main.py는 project_test 폴더 안에 있고, 그리고 그보다 더 상단의 directory 구조까지 절대경로로서 나타내줍니다.
4. 경로 존재 여부 파악
os 모듈에는 특정 directory 또는 파일이 존재하는지를 True/False로 return해주는 exists method가 있습니다.
이와 비슷한 기능이 pathlib 모듈에도 있습니다.
import pathlib
dir_path = pathlib.Path('inputs') / 'text_files' / 'test_contents.txt'
print(dir_path.exists())
-- Result
True
5. 존재하는 파일 list 얻기 (glob)
pathlib 모듈은 glob와 비슷한 기능도 가지고 있습니다.
import pathlib
dir_path = pathlib.Path('.')
print(dir_path)
list_files = list(dir_path.glob('*'))
print(list_files)
-- Result
[PosixPath('main.py'), PosixPath('test_contents.txt'), PosixPath('inputs'), PosixPath('.idea')]
- dir_path = pathlib.Path('.')
.은 현재 경로를 의미합니다.
- list(dir_path.glob('*'))
glob를 사용할 때에는 파일 이름의 pattern을 glob의 parameter로서 전달하는데 여기서는 *를 적었으므로 모든 파일/폴더를 return하라는 의미입니다.
이렇게 glob method의 pattern만 변경해가면서 사용할 수 있습니다.
6. 절대 경로로 변환
import pathlib
dir_path = pathlib.Path('test_code') / 'test' / 'text_file' / 'text_contents.txt'
print(dir_path)
print(dir_path.absolute())
-- Result
test_code/test/text_file/text_contents.txt
/Users/Documents/code/project_test/test_code/test/text_file/text_contents.txt
absolute method를 이용하면 상대경로로 명시된 path를 현재 코드가 실행되는 파일을 기준으로 한 absolute path로 바꿔줍니다.
7. 다양한 경로의 분석
더 상위 경로를 return해주거나, 경로의 구성 요소를 return해주는 등 다양한 경로 분석 기능을 제공합니다.
import pathlib
dir_path = pathlib.Path('test_code') / 'test' / 'text_file' / 'text_contents.txt'
print(dir_path, '\n')
print(dir_path.parent)
print(list(dir_path.parents))
print(dir_path.parts)
-- Result
test_code/test/text_file/text_contents.txt
test_code/test/text_file
[PosixPath('test_code/test/text_file'), PosixPath('test_code/test'), PosixPath('test_code'), PosixPath('.')]
('test_code', 'test', 'text_file', 'text_contents.txt')
위 예시를 봅시다.
- dir_path.parent
parent 속성은 현재 path 객체의 바로 위 parent 경로를 나타내줍니다.
간단하게 말하면 그냥 경로 string에서 가장 하위의 단계(= 가장 오른쪽 단계) 부터 하나를 지운거라고 보면 됩니다.
test_code/test/text_file/text_contents.txt
기존 dir_path가 위와 같았으나 가장 하위에 있는 text_contents.txt를 지우면 parent 속성의 결과와 같아집니다.
- dir_path.parents
parents 속성은 parent 속성과 비슷합니다.
다만 parent 속성이 바로 상위의 경로 하나만 return했다면,
parents 속성은 현재 path 객체에서 가장 오른쪽부터 하나씩 없애가며 가능한 모든 상위 directory 구조를 나타내줍니다.
따라서 그 결과가 여러개일 수 있으므로 list의 형태로 변환해서 봐야합니다.
- dir_path.parts
parts 속성은 현재 path 객체를 구성하는 모든 요소를 하나씩 분할해서 나타내줍니다.
test_code/test/text_file/text_contents.txt
('test_code', 'test', 'text_file', 'text_contents.txt')
결과를 보면 연결된 경로 string이 마치 slash를 기준으로 하나씩 다 나눠진 형태가 return된 것을 알 수 있습니다.