如何在swift4中读取特定文件的行?
问题描述:
Playground中的测试我读取一个字符串数组中的整个文件,每行一个字符串。 但我需要的只是一个特定的行:如何在swift4中读取特定文件的行?
let dir = try? FileManager.default.url(for: .documentDirectory,
in: .userDomainMask, appropriateFor: nil, create: true)
let fileURL = dir!.appendingPathComponent("test").appendingPathExtension("txt")
let text: [String] = try String(contentsOf: fileURL).components(separatedBy: NSCharacterSet.newlines)
let i = 2 // computed before, here to simplify
print(text[i])
有一种方法,以避免读取完整的大文件?
答
我猜你的意思是你想检索索引而不用手动搜索数组,例如for-in
循环。
在Swift 4中,您可以使用Array.index(where:)
结合StringProtocol
的通用contains(_:)
函数来查找您要查找的内容。
让我们假设您正在寻找包含text: [String]
数组中文本“重要内容”的第一行。
你可以使用:
text.index(where: { $0.contains("important stuff") })
在幕后,斯威夫特循环查找的文字,但内置的增强,这应该不是通过text
阵列手动循环有更好的表现。
注意,该搜索的结果可能是nil
如果没有匹配的线都存在。因此,你需要确保它不是nil
使用结果前:
力解开的结果(冒着可怕的fatal error: unexpectedly found nil while unwrapping an Optional value
):
print(text[lineIndex!)
或者,使用if let
声明:
if let lineIndex = stringArray.index(where: { $0.contains("important stuff") }) {
print(text[lineIndex])
}
else {
print("Sorry; didn't find any 'important stuff' in the array.")
}
或使用guard
声明:
guard let lineIndex = text.index(where: {$0.contains("important stuff")}) else {
print("Sorry; didn't find any 'important stuff' in the array.")
return
}
print(text[lineIndex])
答
要查找特定的行而不读取整个文件,可以使用此StreamReader
答案。它包含了在Swift 3中工作的代码。我在Swift 4中对它进行了测试:请参阅我的GitHub回购,TEST-StreamReader,了解我的测试代码。
您仍然需要循环才能到达正确的位置,但是一旦检索到该行,就会返回break
循环。
下面是从StreamReader类SO回答:
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()
}
}
}
https://stackoverflow.com/questions/24581517/read-a-file-url-line-by-line-in-swift#24648951 –
在发布新问题之前,您应该尝试搜索您的答案。 –
我不确定你的意思是“避免阅读完整的大文件”。你有一个'String'对象的数组。这是问题吗?你不想将整个文件读入数组中?否则,如果你知道具体的行号,你的'text [i]'选项就可以工作。或者,你是否问通过循环访问数组来找到某行?而且,如果是这样的话,请添加你如何知道你达到了你想要的范围。 – leanne