I need to read and write data to/from a text file, but I haven\'t been able to figure out how.
I found this sample code in the Swift\'s iBook, but I still don\'t kno
It is recommended to read and write files asynchronously! and it's so easy to do in pure Swift,
here is the protocol:
protocol FileRepository {
func read(from path: String) throws -> String
func readAsync(from path: String, completion: @escaping (Result) -> Void)
func write(_ string: String, to path: String) throws
func writeAsync(_ string: String, to path: String, completion: @escaping (Result) -> Void)
}
As you can see it allows you to read and write files synchronously or asynchronously.
Here is my implementation in Swift 5:
class DefaultFileRepository {
// MARK: Properties
let queue: DispatchQueue = .global()
let fileManager: FileManager = .default
lazy var baseURL: URL = {
try! fileManager
.url(for: .libraryDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("MyFiles")
}()
// MARK: Private functions
private func doRead(from path: String) throws -> String {
let url = baseURL.appendingPathComponent(path)
var isDir: ObjCBool = false
guard fileManager.fileExists(atPath: url.path, isDirectory: &isDir) && !isDir.boolValue else {
throw ReadWriteError.doesNotExist
}
let string: String
do {
string = try String(contentsOf: url)
} catch {
throw ReadWriteError.readFailed(error)
}
return string
}
private func doWrite(_ string: String, to path: String) throws {
let url = baseURL.appendingPathComponent(path)
let folderURL = url.deletingLastPathComponent()
var isFolderDir: ObjCBool = false
if fileManager.fileExists(atPath: folderURL.path, isDirectory: &isFolderDir) {
if !isFolderDir.boolValue {
throw ReadWriteError.canNotCreateFolder
}
} else {
do {
try fileManager.createDirectory(at: folderURL, withIntermediateDirectories: true)
} catch {
throw ReadWriteError.canNotCreateFolder
}
}
var isDir: ObjCBool = false
guard !fileManager.fileExists(atPath: url.path, isDirectory: &isDir) || !isDir.boolValue else {
throw ReadWriteError.canNotCreateFile
}
guard let data = string.data(using: .utf8) else {
throw ReadWriteError.encodingFailed
}
do {
try data.write(to: url)
} catch {
throw ReadWriteError.writeFailed(error)
}
}
}
extension DefaultFileRepository: FileRepository {
func read(from path: String) throws -> String {
try queue.sync { try self.doRead(from: path) }
}
func readAsync(from path: String, completion: @escaping (Result) -> Void) {
queue.async {
do {
let result = try self.doRead(from: path)
completion(.success(result))
} catch {
completion(.failure(error))
}
}
}
func write(_ string: String, to path: String) throws {
try queue.sync { try self.doWrite(string, to: path) }
}
func writeAsync(_ string: String, to path: String, completion: @escaping (Result) -> Void) {
queue.async {
do {
try self.doWrite(string, to: path)
completion(.success(Void()))
} catch {
completion(.failure(error))
}
}
}
}
enum ReadWriteError: LocalizedError {
// MARK: Cases
case doesNotExist
case readFailed(Error)
case canNotCreateFolder
case canNotCreateFile
case encodingFailed
case writeFailed(Error)
}