아리의 iOS 탐구생활

[Swift/iOS] FileManager로 파일 생성(쓰기), 읽기, 삭제하기 본문

Swift/iOS

[Swift/iOS] FileManager로 파일 생성(쓰기), 읽기, 삭제하기

Ari Lee 2021. 8. 27. 11:31
반응형
 

Apple Developer Documentation

 

developer.apple.com

아이폰 앱마다 자기만의 공간을 가지고 있는데, 공간을 관리하는 매니저라 생각하면 같다. 공간은 일반 , 윈도우처럼 Document 폴더, Download 폴더 등등 다양한 종류의 폴더가 있다.

 

 

경로(URL) 접근하기

다른 작업을 하기전 공통 사항인 해당 폴더로 접근하는 방법을 먼저 알아보자.

// 파일매니저 인스턴스 생성
let fileManager = FileManager.default 
// 사용자의 문서 경로
let documentPath: URL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]

urls라는 메소드는 요청된 도메인에서 지정된 공통 디렉토리에 대한 URL배열을 리턴해주는 메소드이다.

  • for: 폴더를 정해주는 요소. Download 혹은 Document 등등…
  • in: 제한을 걸어주는 요소. 그 이상은 못가게 하는…

 

애플이 주석을 굉장히 잘 써놨으므로 좀더 디테일하게 보면 아래와 같다.

굉장히 많다. 그 중 친숙해 보이는 몇개만 가져왔다. 이런식으로 접근 폴더를 지정해준다.

 

  • for enum 값들 (Objective C Enum)
documentDirectory   // documents (Documents)
developerDirectory  // (Developer) DEPRECATED - there is no one single Developer directory.
desktopDirectory    // location of user's desktop
downloadsDirectory  // location of the user's "Downloads" directory
musicDirectory      // location of user's Music directory (~/Music)
...

 

  • in enum 값들 (Swift Enum)
public static var localDomainMask: FileManager.SearchPathDomainMask { get } 
// local to the current machine --- place to install items available to everyone on this machine (/Library)

public static var networkDomainMask: FileManager.SearchPathDomainMask { get } 
// publically available location in the local area network --- place to install items available on the network (/Network)

public static var systemDomainMask: FileManager.SearchPathDomainMask { get } 
// provided by Apple, unmodifiable (/System)

public static var allDomainsMask: FileManager.SearchPathDomainMask { get } 
// all domains: all of the above and future items

터미널을 조금이라도 써봤다면 뒤에 괄호만 봐도 쉽게 이해할 있을 것이다.

 

 

 

경로(URL) 추가

appendingPathComponent 메소드를 사용하여 경로를 새롭게 추가해줄 수 있다.  URL을 반환한다.

아래 예제에서는 "새 폴더" 라는 경로를 추가해주었다.

// FileManager 인스턴스 생성
let fileManager: FileManager = FileManager.default
// 사용자의 문서 경로
let documentPath: URL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
// 파일을 저장할 디렉토리 경로(URL) 반환 (경로 추가)
let directoryPath: URL = documentPath.appendingPathComponent("새 폴더")

"새 폴더"로 경로를 추가해줬다고 해서 폴더가 생성된 것이 아니다. 말 그대로 경로(URL)만 설정해준 것이라고 생각하면 된다.

 

 

자, 그러면 폴더 추가는 어떻게 할까?

 

 

Directory(폴더)를 추가하는 방법

do {
    // 아까 만든 디렉토리 경로에 디렉토리 생성 (폴더가 만들어진다.)
    try fileManager.createDirectory(at: directoryPath, withIntermediateDirectories: false, attributes: nil)
} catch let e {
    print(e.localizedDescription)
}

아까 새로 만들어주었던 "새 폴더" 의 경로에 Directory를 생성하여 폴더를 만들어주었다. 경로에 직접 접근하면 폴더가 만들어진 것을 확인할 수 있다.

 

createDirectory 메소드의 파라미터들을 살펴보자.

  • at: 경로 및 폴더명, 위에서 만든 URL 사용
  • withIntermediateDirectories: “중간 디렉토리들도 만들거니?” 라는 의미
  • attributes: 파일 접근 권한, 그룹 등등 폴더 속성 정의

 

Xcode에서 반환하는 경로(URL)을 타고 눈으로 직접 확인하고 싶다면, Finder에서 CMD + Shift + G를 누르게 된다면,

이러한 검색창이 뜨는데, directoryPath가 반환하는 URL을 그대로 복사하여 붙여넣으면 접근할 수 있다.

경로를 보면 hi.txt가 있는데 지금부터 FileManager를 이용하여 hi.txt를 만들어줄 것이다.

 

 

Directory(폴더)에 파일 추가하는 방법

자, 먼저 txt파일을 생성해줘야 한다.

폴더를 만들 때와 똑같이 경로(URL)를 먼저 설정해줘야 한다.

let textPath: URL = directoryPath.appendingPathComponent("hi.txt")

그리고 해당 경로에 String 타입을 Data로 변환하여 '쓰기'를 진행하면 텍스트파일이 생성되면서 안에 내가 변환한 문자열 데이터가 작성되어 만들어진다.

// 아까 만든 'hi.txt' 경로에 텍스트 쓰기
if let data: Data = "안녕하세요.".data(using: String.Encoding.utf8) { // String to Data
    do {
        try data.write(to: textPath) // 위 data를 "hi.txt"에 쓰기
    } catch let e {
        print(e.localizedDescription)
    }
}

파일을 생성하였으니 해당 파일을 읽어오려면 쓰기에서 했던 작업을 반대로 해주면 된다.

 

 

 

파일을 불러오는 방법

// 만든 파일 불러와서 읽기.
do {
    let dataFromPath: Data = try Data(contentsOf: textPath) // URL을 불러와서 Data타입으로 초기화
    let text: String = String(data: dataFromPath, encoding: .utf8) ?? "문서없음" // Data to String
    print(text) // 출력
} catch let e {
    print(e.localizedDescription)
}

아까 hi.txt 경로(불러올 파일의 경로)를 Data 타입으로 초기화 해주고, Data 타입을 String으로 인코딩 해주게 되면 읽을 수 있게 된다.

 

 

 

생성한 파일을 삭제하려면 어떻게 하는거지?

 

 

 

파일을 삭제하는 방법

// 파일을 삭제한다.
do {
    try fileManager.removeItem(at: textPath)
} catch let e {
    print(e.localizedDescription)
}

removeItem 메소드를 호출하여 삭제할 파일의 경로(URL)을 전달해주면 된다.

 

 

삭제를 하고 Finder를 확인해보거나 불러오려고 다시 읽기를 시도하면 에러가 발생하는 것을 확인할 수 있다.

do {
    let dataFromPath: Data = try Data(contentsOf: textPath) // URL을 불러와서 Data타입으로 초기화
    let text: String = String(data: dataFromPath, encoding: .utf8) ?? "문서없음" // Data to String
    print(text) // 출력
} catch let e {
    print(e.localizedDescription) // The file “hi.txt” couldn’t be opened because there is no such file.
}

 

 

 

 

Full Code

// FileManager 인스턴스 생성
let fileManager: FileManager = FileManager.default
// 사용자의 문서 경로
let documentPath: URL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
// 파일을 저장할 디렉토리 경로(URL) 반환 (경로 추가)
let directoryPath: URL = documentPath.appendingPathComponent("새 폴더")
// 디렉토리에 만들 '파일이름.확장자' 설정 (경로에 'hi.txt'의 새 경로 추가)
let textPath: URL = directoryPath.appendingPathComponent("hi.txt")


// 파일매니저로 디렉토리 생성하기
do {
    // 아까 만든 디렉토리 경로에 디렉토리 생성 (폴더가 만들어진다.)
    try fileManager.createDirectory(at: directoryPath, withIntermediateDirectories: false, attributes: nil)
} catch let e {
    print(e.localizedDescription)
}

// 아까 만든 'hi.txt' 경로에 텍스트 쓰기
if let data: Data = "안녕하세요.".data(using: String.Encoding.utf8) { // String to Data
    do {
        try data.write(to: textPath) // 위 data를 "hi.txt"에 쓰기
    } catch let e {
        print(e.localizedDescription)
    }
}

// 만든 파일 불러와서 읽기.
do {
    let dataFromPath: Data = try Data(contentsOf: textPath) // URL을 불러와서 Data타입으로 초기화
    let text: String = String(data: dataFromPath, encoding: .utf8) ?? "문서없음" // Data to String
    print(text) // 출력
} catch let e {
    print(e.localizedDescription)
}

// 파일을 삭제한다.
do {
    try fileManager.removeItem(at: textPath)
} catch let e {
    print(e.localizedDescription)
}

// 삭제한 파일을 읽으려니 에러 발생
do {
    let dataFromPath: Data = try Data(contentsOf: textPath)
    let text: String = String(data: dataFromPath, encoding: .utf8) ?? "문서없음"
    print(text)
} catch let e {
    print(e.localizedDescription) // The file “hi.txt” couldn’t be opened because there is no such file.
}

 

 

QnA

텍스트나 이미지 말고 GIF 등등 다른건 어떻게 관리하죠?

NSDate 형식으로 아래처럼 손쉽게 변경할 있다.

// Archive Data
let archivedData = NSKeyedArchiver.archivedData(withRootObject: file)

// Unarchive Data
let unarchivedData = NSKeyedUnarchiver.unarchiveObject(with: file as Data)

 

 

애플 내장 앱중 File App 이랑 관련이 있나요?

관련 있다. 프로젝트 내에 설정을 하면 File App 해당 어플에 접근할 있게 된다.

 

 

 

 

 

Reference

 

Swift - FileManager

나만의 공간

jiseobkim.github.io

 

반응형
Comments