FileManager 공부
iOS 상에서 파일 관련 작업을 해주는 FileManager에 대해 공부하려 한다.
FileManager란?
iOS
와 macOS
에서 파일을 다룰 수 있게 해주는 클래스로 iOS 2.0 이상, macOS 10.0 이상부터 사용 가능하다. 파일 시스템과 상호작용하게끔 해주며 파일과 디렉토리의 위치 결정(locate)
, 생성(create)
, 복사(copy)
, 옮기기(move)
가 가능하다. 물론 특정 파일이나 디렉토리의 정보를 얻어오는 것도 지원된다.
특정 파일의 위치를 명시할 때, Apple은 NSString
객체 대신 NSURL
객체를 사용하는 것을 권장하는데, 이는 시스템 내부적으로 URL
객체가 경로 정보를 더 효율적인 표현으로 바꿔주기 때문이다.
파일이나 디렉토리를 옮기거나, 복사하거나, 링크하거나, 삭제할 때 FileManagerDelegate
프로토콜을 따르는 delegate
를 사용할 수 있다. 이 delegate
는 FileManager
의 동작을 확인하거나, 에러가 일어났을 때 진행할 것인지를 결정한다.
FileManager
클래스는 iOS 5.0, macOS 10.7 이상부터 iCloud에 저장된 아이템들을 관리할 수 있게 되었다. iCloud의 파일들을 조작하면 iCloud와 동기화된 모든 기기의 파일들이 바뀌게 된다.
FileManagerDelegate에 대해
FileManager
의 동작들을 관리하는 옵셔널한 메서드들을 가지고 있다. NSURL
과 NSString
객체 둘 다를 받는 메서드들을 가지고 있지만 FileManager
와 마찬가지로 NSURL
객체를 선호한다.
이것을 사용할 때 주의할 것은 직접 생성한 FileManager
의 인스턴스와 연결해야 한다는 것이다. shared한 FileManager.default
를 사용하면 안 된다.
FileManager
의 동작 별로 다음과 같은 메서드들을 가지고 있다.
- 동작을 시작해도 되는지 확인:
should(동작)ItemAt
- 에러가 일어난 뒤 지속할지 확인:
shouldProceedAfterError
How to use
FileManager
클래스는 싱글턴 객체를 제공하며 여러 스레드에서 안전하게 동작이 가능하다. 다음과 같이 접근한다.
1 | FileManager.default |
그러나 위에서 언급했듯이 delegate
를 사용해 move
, copy
, remove
, link
동작들의 상태를 체크하려면 직접 FileManager
인스턴스를 만들어야 한다. 그리고 인스턴스에 delegate
를 연결한다.
1 | let fileManager = FileManager() |
위치 지정
FileManager
의 인스턴스 메서드인 urls(for:in:)
로 특정 디렉토리의 URL의 배열을 얻어올 수 있다. 이 메서드는 두 가지 인자를 가진다.
- directory:
FileManager.SearchPathDirectory
타입이며 탐색할 디렉토리를 지정한다. - domainMask:
FileManager.SearchPathDomainMask
타입이며 파일 시스템의도메인(domain)
을 지정한다.
여기서 중요한 것은 도메인이 디렉토리를 포함해야 한다는 것이다.
반환되는 NSURL
의 배열은 Domain Mask
의 상수의 순서대로 정렬되어 있는데, 이는 System 도메인부터 User 도메인의 순서이다.
1 | guard let documentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else { return } |
쓰기
디렉토리
FileManager
의 인스턴스 메서드인 createDirectory(at:withIntermediateDirectories:attributes:)로 특정 URL에 새로운 디렉토리를 생성할 수 있다. createIntermediates
와 attributes
인자는 디렉토리의 생성과 관련된 설정을 하는 것이다.
물론 I/O 작업이기 때문에 실패할 경우 에러를 반환하는 메서드이다. try-catch
문으로 에러에 대한 처리를 해주거나 아래와 같이 옵셔널하게 처리한다.
1 | try? fileManager.createDirectory(at: directoryPath, withIntermediateDirectories: false, attributes: nil) |
파일
파일의 생성은 createFile(atPath:contents:attributes:)
로 할 수 있지만 지금은 String
파일로 txt
파일을 만들어보려고 한다.
1 | let textFilePath = directoryPath.appendingPathComponent("Alpaca.text") |
위의 에에서는 String Protocol
의 write(to:atomically:encoding:)
메서드로 위에서 지정한 textFilePath
에 텍스트 파일을 만든다.
읽기
디렉토리
디렉토리 안에 있는 컨텐츠를 알아보는 메서드는 contentsOfDirectory(at:includingPropertiesForKeys:options:)
로 컨텐츠들의 URL
배열을 반환한다.
1 | if let documentsURL = try? fileManager.contentsOfDirectory(at: documentDirectory, includingPropertiesForKeys: nil, options: .skipsHiddenFiles) { |
파일
파일은 파일 경로인 URL
을 인자값으로 갖는 Data
타입의 초기화 메서드 init(contentsOf:options:)
로 받을 수 있다.
다음 예제에서는 String
타입의 초기화 메서드 init(contentsOf:)
로 파일 경로로부터 문자열을 읽어올 것이다.
1 | guard let alpacaText = try? String(contentsOf: textFilePath) else { return } |