[ios] File System (2)
안녕하세요. 지난 번 iOS의 파일 시스템의 포스팅에서는 전반적인 구조와 개념을 알아보았습니다. 오늘은 본격적으로 코드를 통해 파일 시스템을 다루어보도록 하겠습니다. 지난 포스팅을 보지 않으신 분들은 해당 포스팅을 먼저 읽어보시는 것을 추천드립니다.
지난 포스팅에서 언급하였듯이 iOS는 각각의 어플리케이션들이 샌드박스 형태로 존재하므로 특별한 경우가 아닌 이상 본인의 영역 외의 공간에는 접근할 수 없습니다. 오늘의 포스팅에서는 iOS내의 파일 시스템을 다루기 위해 FileManager
클래스를 사용할 것입니다.
FileManager란
FileManager
클래스는 iOS 내에서 파일과 디렉토리의 생성, 이동, 읽기, 쓰기 행위와 같은 기본적인 동작과 제어를 할 때 사용됩니다.
macOS와 iOS에서는 표준 UNIX Convention으로 경로명을 정의합니다. 그러므로 상대경로와 절대경로에 대한 개념도 존재하며 파일 시스템의 루트 디렉토리 경로는 '/' 가 됩니다.
이젠 코드로 살펴보겠습니다.
위의 메소드를 viewDidLoad()
에서 호출해주세요.
FileManager.default
를 통해 FileManager
의 default 객체에 대한 참조를 얻을 수 있습니다.
- 현재 디렉토리 경로를 얻고 이를 출력시켜봅니다. 결과는
"Current Path :/ "
가 될 것입니다. 즉 어플리케이션이 실행되면 현재 작업 경로는 루트 디렉토리가 됩니다. 이제 여기서 Documents/
와 tmp/
에 접근하여 파일과 디렉토리에 대한 기본적인 행위들을 수행할 수 있습니다.
Domain
본격적으로 FileManager
를 사용해보기 전에 먼저 도메인이라는 개념부터 알아보도록 하겠습니다. 공식문서에서 설명하는 macOS에서 도메인의 개념은 다음과 같습니다. ( 보다 정확한 정보의 전달을 위해 몇몇의 단어는 그대로 사용하였습니다.)
macOS에서 파일 시스템은 파일과 resource의 사용 용도에 따라 여러개의 도메인으로 나누어져 있습니다. 이러한 영역 분할은 특정 파일들만을 고려해야하는 사용자에게 simplicity를 제공합니다. 파일들을 도메인에 따라 정렬하면 시스템이 해당 도메인 별 접근 권한을 적용하고 이로인해 권한이 없는 사용자로부터의 의도적이거나 부주의한 접근을 막을 수 있습니다.
도메인의 종류는 다음과 같습니다.
- User - User 도메인은 현재 시스템에 로그인한 사용자에 대한 resource들을 포함합니다.
- Local - 어플리케이션과 같이 해당 컴퓨터의 사용자가 모두 공유하는 자원들을 포함합니다. 이 도메인은 시스템에 의해 관리되고 권한이 있는 사용자만이 이 도메인에 자원을 추가하거나 수정, 삭제할 수 있습니다.
- System - 애플에 의해 설치된 시스템 소프트웨어를 포함합니다. 시스템이 실행되는데 필요한 자원들이 이곳에 위치합니다. 사용자는 이 도메인에 대한 어떠한 권한도 허용되지 않습니다.
FileManager 사용해보기
- urls(for:,in:)
이전 포스팅에서 언급하였듯이 각각의 어플리케이션은 데이터를 쓰고 읽는 것이 허용이 되는 자신만의 공간인 Documents/
와 tmp/
디렉토리가 존재합니다. 이 두 디렉토리의 경로는 어플리케이션 마다 모두 다르기 때문에 직접 접근하는 것이 아니라 FileManager
가 제공하는 api를 통해 접근해야 합니다.
.documentDirectory
는 Documents/
디렉토리를 지칭하며 .userDomainMask
는 macOS에 존재하는 도메인의 개념과 같습니다. 위의 변수로 넘어가는 .userDomainMask
의 의미는 홈 디렉토리의 하위에서 Documents
디렉토리에 대한 url을 반환해달라는 의미입니다. 홈 디렉토리가 User 도메인에 포함된다는 것을 알 수 있습니다.
- url 요청에 대한 응답으로 여러 경로들이 있을 수 있지만 여기서는 하나만이 존재하기 때문에 배열의 첫번째 값에 해당하는 url이
Documents/
디렉토리의 경로가 됩니다.
macOS에서의 도메인의 개념은 어느정도 이해를 했으나 iOS의 도메인의 개념은 아직 이 정도의 수준으로밖에 이해하지 못하였습니다. 추후에 기회가 되면 더 알아보고 관련 내용을 업로드 하도록 하겠습니다.
출력결과를 확인해보세요. 실제 디바이스와 시뮬레이터간의 출력 결과와 형식은 약간의 차이가 존재합니다.
Simulator
/Users/<user name>/Library/Developer/CoreSimulator/Devices/<device id>/data/Containers/Data/Application/<app id>/Documents
- user name : 현재 시스템에 접속한 사용자의 이름
- device id : 현재 어플리케이션이 돌아가는 디바이스의 고유한 id 값
- app id : 현재 실행중인 어플리케이션의 고유 id 값
Device
/var/mobile/Containers/Data/Application/<app id>/Documents
- changeCurrentDirectoryPath(_:)
위에서 처럼 Documents/
나 tmp/
의 디렉토리 경로를 알 수 있다면 원하는 디렉토리로 이동할 수 있어야 합니다.
이제 출력 결과를 보면 현재 작업 경로가 Documents/
디렉토리로 바뀐 것을 확인할 수 있습니다. 만일 해당 디렉토리가 존재하지 않거나 해당 디렉토리로의 접근이 허용되지 않으면 실패하게 됩니다.
Implementation
저는 이런 FileManager
를 통해 서버로부터 mp3 파일을 다운받아 디바이스에 저장하는 것을 코드로 구현하였습니다. 먼저 저는 서버로부터 파일을 다운 받기 위해 Alamofire
라는 라이브러리를 사용했습니다.
서버로부터 mp3 다운로드
위는 특정 에피소드에 해당하는 mp3 파일을 다운로드 받는 코드입니다. 오늘의 포스팅에서 주목해야할 점은 .suggestedDownloadDestination()
입니다. 다운로드될 파일의 경로를 직접 지정해줄 수도 있지만 Alamofire
는 default경로로 .suggestedDownloadDestination()
를 제공합니다.
해당 메소드의 정의로 가보면 어떤 경로가 default로 지정이 되어있는지를 확인할 수 있습니다.
default 디렉토리는 .userDomainMask
의 .documentDirectory
가 된다는 것을 알 수 있습니다. 왜 이곳이 default 디렉토리가 되는 이유는 user-generate 데이터는 이곳에 저장되어야 하기 때문입니다. 자세한 사항은 이전 포스팅을 참고해주세요.
그러므로 다운로드된 mp3파일을 재생시키기 위해서는 위의 디렉토리에서 접근해야합니다. 하지만 여기서 주의하셔야할 것이 있습니다. 저도 그랬고 많은 분들이 위의 다운로드 경로를 같이 저장하여 추후에 다운로드 된 경로로 접근하려합니다.
하지만 iOS에서는 어플리케이션이 종료되고 다시 실행될 때마다 해당 디렉토리의 경로를 지속해서 바꿉니다. 그러므로 문자열의 형태로 저장된 파일의 경로는 다음 어플리케이션 실행시에는 존재하지 않는 경로가 되는 것입니다. 그러므로 반드시 위에서 사용한 urls(for:,in:)
메소드와 해당 파일의 이름을 통해 접근해야합니다.
저는 저장된 문자열 형태의 경로를 다음과 같이 재사용하였습니다.
파일이 저장된 경로를 저장하였지만 저는 이 경로에서 .lastPathComponent
를 이용해 파일의 이름만을 사용하였습니다. 그리고 실제 저장된 경로를 urls(for:,in:)
을 통해 접근하여 파일의 이름을 붙여 해당 파일에 접근하였습니다.
마무리
이렇게 iOS의 파일 시스템에 대해 공부를 하면서 보다 iOS의 구조를 잘 이해하는 계기가 되었습니다. 정말 알찬 내용이었다고 스스로에게 만족감을 느끼고 있습니다. 그리고 저 자신이 iOS를 제대로 이해하고 사용하는 개발자가 되는데 한 발 다가서는 계기가 되었으면 합니다. 감사합니다.
Source : github
참고자료
- File Basics
- Working directories with Swift on iOS10
- 스위프트로 파일 다루기