在Swift中逐行读取文本文件?

Sca*_*nvy 38 arrays text nsstring ios swift

刚开始学习Swift,我已经从文本文件中读取了代码,应用程序显示了整个文本文件的内容.如何逐行显示并多次调用该行?

TextFile.txt包含以下内容.

  1. 香蕉
  2. 苹果
  3. 草莓
  4. 蓝莓
  5. 黑茶

以下是目前的......

  if let path = NSBundle.mainBundle().pathForResource("TextFile", ofType: "txt"){
        var data = String(contentsOfFile:path, encoding: NSUTF8StringEncoding, error: nil)
            if let content = (data){
                TextView.text = content
    }
Run Code Online (Sandbox Code Playgroud)

如果还有其他方式,请告诉我.非常感激

Cal*_*leb 77

Swift 3.0

if let path = Bundle.main.path(forResource: "TextFile", ofType: "txt") {
    do {
        let data = try String(contentsOfFile: path, encoding: .utf8)
        let myStrings = data.components(separatedBy: .newlines)
        TextView.text = myStrings.joined(separator: ", ")
    } catch {
        print(error)
    }
}
Run Code Online (Sandbox Code Playgroud)

变量myStrings应该是数据的每一行.

使用的代码来自: 用Obj-C编写的iOS SDK中使用NSString 逐行读取文件

检查以前版本的Swift的编辑历史记录.

  • 这不会逐行读取文本文件.它读取整个文件,将其全部保存到数据中,然后将所有文件作为一个行数组返回. (63认同)
  • 在@algal注释之后,此答案不适用于很大的文件。对于需要一点一点读取大文件块的人,请查看以下答案:/sf/ask/1720706221/ (2认同)

Jas*_*oss 20

斯威夫特 5.2

下面的解决方案显示了如何一次读取一行。这与将整个内容读入内存完全不同。如果您有一个大文件要读取,则逐行读取可以很好地扩展。将整个文件放入内存不能很好地扩展大文件。

下面的示例使用 while 循环,当没有更多行时退出,但您可以根据需要选择不同数量的行来读取。

该代码的工作原理如下:

  1. 创建一个 URL 来说明文件所在的位置
  2. 确保文件存在
  3. 打开文件进行阅读
  4. 设置一些用于读取的初始变量
  5. 使用读取每一行 getLine()
  6. 完成后关闭文件

如果你愿意,你可以让代码不那么冗长;我已经添加了注释来解释变量的目的是什么。

斯威夫特 5.2

import Cocoa

// get URL to the the documents directory in the sandbox
let home = FileManager.default.homeDirectoryForCurrentUser

// add a filename
let fileUrl = home
    .appendingPathComponent("Documents")
    .appendingPathComponent("my_file")
    .appendingPathExtension("txt")


// make sure the file exists
guard FileManager.default.fileExists(atPath: fileUrl.path) else {
    preconditionFailure("file expected at \(fileUrl.absoluteString) is missing")
}

// open the file for reading
// note: user should be prompted the first time to allow reading from this location
guard let filePointer:UnsafeMutablePointer<FILE> = fopen(fileUrl.path,"r") else {
    preconditionFailure("Could not open file at \(fileUrl.absoluteString)")
}

// a pointer to a null-terminated, UTF-8 encoded sequence of bytes
var lineByteArrayPointer: UnsafeMutablePointer<CChar>? = nil

// the smallest multiple of 16 that will fit the byte array for this line
var lineCap: Int = 0

// initial iteration
var bytesRead = getline(&lineByteArrayPointer, &lineCap, filePointer)

defer {
    // remember to close the file when done
    fclose(filePointer)
}

while (bytesRead > 0) {
    
    // note: this translates the sequence of bytes to a string using UTF-8 interpretation
    let lineAsString = String.init(cString:lineByteArrayPointer!)
    
    // do whatever you need to do with this single line of text
    // for debugging, can print it
    print(lineAsString)
    
    // updates number of bytes read, for the next iteration
    bytesRead = getline(&lineByteArrayPointer, &lineCap, filePointer)
}
Run Code Online (Sandbox Code Playgroud)


iUr*_*rii 16

如果您有一个巨大的文件并且不想使用 等将所有数据加载到内存中StringData您可以使用readLine()从标准输入逐行读取内容直到达到 EOF 的函数。

let path = "path/file.txt"
guard let file = freopen(path, "r", stdin) else {
    return
}
defer {
    fclose(file)
}

while let line = readLine() {
    print(line)
}
Run Code Online (Sandbox Code Playgroud)

  • 我不明白为什么这个答案没有得到更多的支持。这是迄今为止最正确的答案,因为它实际上以非常简单的方式逐行读取文件。 (5认同)

Rob*_*Rob 10

在 iOS 15.0+ 和 macOS 12.0+ 中,通过 Swift 并发 和FileHandle,您可以使用linesfrom bytes

func readLineByLine(from fileUrl: URL) async throws {
    let handle = try FileHandle(forReadingFrom: fileUrl)
    for try await line in handle.bytes.lines {
        // do something with `line`
    }
    try handle.close()
}
Run Code Online (Sandbox Code Playgroud)

或者,也可以使用linesfrom URL

func readLineByLine(from fileUrl: URL) async throws {
    for try await line in fileUrl.lines {
        // do something with `line`
    }
}
Run Code Online (Sandbox Code Playgroud)

这两种方法都避免了将整个资产一次性加载到内存中,因此内存效率很高。


Ner*_*ode 6

在 Swift 5.0 中执行此操作的最简单、最简单的方法可能如下:

import Foundation

// Determine the file name
let filename = "main.swift"

// Read the contents of the specified file
let contents = try! String(contentsOfFile: filename)

// Split the file into separate lines
let lines = contents.split(separator:"\n")

// Iterate over each line and print the line
for line in lines {
    print("\(line)")
}
Run Code Online (Sandbox Code Playgroud)

注意:这会将整个文件读入内存,然后迭代内存中的文件以生成行......

信用转到:https ://wiki.codermerlin.com/mediawiki/index.php/Code_Snippet:_Print_a_File_Line-by-Line

  • 这不会逐行读取文本文件。它读取整个文件,将其全部保存到一个字符串中,将其拆分为一个字符串数组,然后逐个打印它们。如果您的字符串太大而无法放入内存,则会失败。 (21认同)

alg*_*gal 5

这并不漂亮,但我相信它有效(在 Swift 5 上)。这使用底层 POSIXgetline命令进行迭代和文件读取。

typealias LineState = (
  // pointer to a C string representing a line
  linePtr:UnsafeMutablePointer<CChar>?,
  linecap:Int,
  filePtr:UnsafeMutablePointer<FILE>?
)

/// Returns a sequence which iterates through all lines of the the file at the URL.
///
/// - Parameter url: file URL of a file to read
/// - Returns: a Sequence which lazily iterates through lines of the file
///
/// - warning: the caller of this function **must** iterate through all lines of the file, since aborting iteration midway will leak memory and a file pointer
/// - precondition: the file must be UTF8-encoded (which includes, ASCII-encoded)
func lines(ofFile url:URL) -> UnfoldSequence<String,LineState>
{
  let initialState:LineState = (linePtr:nil, linecap:0, filePtr:fopen(fileURL.path,"r"))
  return sequence(state: initialState, next: { (state) -> String? in
    if getline(&state.linePtr, &state.linecap, state.filePtr) > 0,
      let theLine = state.linePtr  {
      return String.init(cString:theLine)
    }
    else {
      if let actualLine = state.linePtr  { free(actualLine) }
      fclose(state.filePtr)
      return nil
    }
  })
}
Run Code Online (Sandbox Code Playgroud)

以下是您可以如何使用它:

for line in lines(ofFile:myFileURL) {
  print(line)
}
Run Code Online (Sandbox Code Playgroud)