在Swift中逐行读取文件 URL

在Swift中逐行读取文件 URL,第1张

在Swift中逐行读取文件/ URL

(该代码现在适用于Swift 2.2 / Xpre 7.3。如果有人需要,可以在编辑历史记录中找到旧版本。最后提供了Swift 3的更新版本。)

以下Swift代码从如何逐行从NSFileHandle中读取数据的各种答案中获得了很大的启发
。它从块中读取文件,并将完整的行转换为字符串。

n
可以使用可选参数设置默认的行定界符(),字符串编码(UTF-8)和块大小(4096)。

class StreamReader  {    let encoding : UInt    let chunkSize : Int    var fileHandle : NSFileHandle!    let buffer : NSMutableData!    let delimdata: NSData!    var atEof : Bool = false    init?(path: String, delimiter: String = "n", encoding : UInt = NSUTF8StringEncoding, chunkSize : Int = 4096) {        self.chunkSize = chunkSize        self.encoding = encoding        if let fileHandle = NSFileHandle(forReadingAtPath: path), delimData = delimiter.dataUsingEncoding(encoding), buffer = NSMutableData(capacity: chunkSize)        { self.fileHandle = fileHandle self.delimData = delimData self.buffer = buffer        } else { self.fileHandle = nil self.delimData = nil self.buffer = nil return nil        }    }    deinit {        self.close()    }    /// Return next line, or nil on EOF.    func nextLine() -> String? {        precondition(fileHandle != nil, "Attempt to read from closed file")        if atEof { return nil        }        // Read data chunks from file until a line delimiter is found:        var range = buffer.rangeOfData(delimData, options: [], range: NSMakeRange(0, buffer.length))        while range.location == NSNotFound { let tmpData = fileHandle.readDataOfLength(chunkSize) if tmpData.length == 0 {     // EOF or read error.     atEof = true     if buffer.length > 0 {         // Buffer contains last line in file (not terminated by delimiter).         let line = NSString(data: buffer, encoding: encoding)         buffer.length = 0         return line as String?     }     // No more lines.     return nil } buffer.appendData(tmpData) range = buffer.rangeOfData(delimData, options: [], range: NSMakeRange(0, buffer.length))        }        // Convert complete line (excluding the delimiter) to a string:        let line = NSString(data: buffer.subdataWithRange(NSMakeRange(0, range.location)), encoding: encoding)        // Remove line (and the delimiter) from the buffer:        buffer.replaceBytesInRange(NSMakeRange(0, range.location + range.length), withBytes: nil, length: 0)        return line as String?    }    /// Start reading from the beginning of file.    func rewind() -> Void {        fileHandle.seekToFileOffset(0)        buffer.length = 0        atEof = false    }    /// Close the underlying file. No reading must be done after calling this method.    func close() -> Void {        fileHandle?.closeFile()        fileHandle = nil    }}

用法:

if let aStreamReader = StreamReader(path: "/path/to/file") {    defer {        aStreamReader.close()    }    while let line = aStreamReader.nextLine() {        print(line)    }}

您甚至可以将阅读器与for-in循环一起使用

for line in aStreamReader {    print(line)}

通过实施

SequenceType
协议(比较http://robots.thoughtbot.com/swift-
sequences
):

extension StreamReader : SequenceType {    func generate() -> AnyGenerator<String> {        return AnyGenerator { return self.nextLine()        }    }}

Swift 3 / Xpre 8 beta 6更新: 还要“现代化”使用

guard
和新
Data
值类型:

class StreamReader  {    let encoding : String.Encoding    let chunkSize : Int    var fileHandle : FileHandle!    let delimdata: Data    var buffer : Data    var atEof : Bool    init?(path: String, delimiter: String = "n", encoding: String.Encoding = .utf8,          chunkSize: Int = 4096) {        guard let fileHandle = FileHandle(forReadingAtPath: path), let delimData = delimiter.data(using: encoding) else {     return nil        }        self.encoding = encoding        self.chunkSize = chunkSize        self.fileHandle = fileHandle        self.delimData = delimData        self.buffer = Data(capacity: chunkSize)        self.atEof = false    }    deinit {        self.close()    }    /// Return next line, or nil on EOF.    func nextLine() -> String? {        precondition(fileHandle != nil, "Attempt to read from closed file")        // Read data chunks from file until a line delimiter is found:        while !atEof { if let range = buffer.range(of: delimData) {     // Convert complete line (excluding the delimiter) to a string:     let line = String(data: buffer.subdata(in: 0..<range.lowerBound), encoding: encoding)     // Remove line (and the delimiter) from the buffer:     buffer.removeSubrange(0..<range.upperBound)     return line } let tmpData = fileHandle.readData(ofLength: chunkSize) if tmpData.count > 0 {     buffer.append(tmpData) } else {     // EOF or read error.     atEof = true     if buffer.count > 0 {         // Buffer contains last line in file (not terminated by delimiter).         let line = String(data: buffer as Data, encoding: encoding)         buffer.count = 0         return line     } }        }        return nil    }    /// Start reading from the beginning of file.    func rewind() -> Void {        fileHandle.seek(toFileOffset: 0)        buffer.count = 0        atEof = false    }    /// Close the underlying file. No reading must be done after calling this method.    func close() -> Void {        fileHandle?.closeFile()        fileHandle = nil    }}extension StreamReader : Sequence {    func makeIterator() -> AnyIterator<String> {        return AnyIterator { return self.nextLine()        }    }}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/4894175.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-12
下一篇 2022-11-12

发表评论

登录后才能评论

评论列表(0条)

保存