Read and write a String from text file

前端 未结 21 1415
别跟我提以往
别跟我提以往 2020-11-22 00:02

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

21条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-11-22 00:39

    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)
    }
    
    

提交回复
热议问题