当前位置: 首页 > 知识库问答 >
问题:

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

邵和硕
2023-03-14

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

文本文件.txt包含以下内容:

1. Banana 
2. Apple
3. pear
4. strawberry
5. blueberry
6. blackcurrant

以下是目前的…

  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
    }

如果有别的方法,请告诉我。非常感谢。

共有3个答案

于嘉许
2023-03-14

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

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

以下是您可以使用它的方法

for line in lines(ofFile:myFileURL) {
  print(line)
}
邓阳嘉
2023-03-14

雨燕5.5

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

下面的例子使用了一个while循环,当没有更多的行时会退出,但是如果愿意,您可以选择不同的行数来读取。

代码的工作原理如下:

  1. 创建一个告诉文件位置的URL
  2. 确保文件存在
  3. 打开文件读取
  4. 设置一些读取的初始变量
  5. 使用getLine()
  6. 读取每一行
  7. 完成后关闭文件并释放缓冲区

如果您愿意,您可以使代码不那么冗长;我已经包含了注释来解释变量的用途。

雨燕5.5

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

// see the official Swift documentation for more information on the `defer` statement
// https://docs.swift.org/swift-book/ReferenceManual/Statements.html#grammar_defer-statement
defer {
    // remember to close the file when done
    fclose(filePointer)

    // The buffer should be freed by even if getline() failed.
    lineByteArrayPointer?.deallocate()
}

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


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)
}
周云
2023-03-14

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

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

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

检查Swift以前版本的编辑历史。

 类似资料:
  • 问题内容: 我刚刚开始学习Swift。我有要从文本文件读取的代码,应用程序显示了整个文本文件的内容。如何显示一行一行并多次调用该行? 包含以下内容: 以下是目前的情况。 如果还有另一种方法,请告诉我。将不胜感激。 问题答案: 斯威夫特3.0 该变量应该是数据的每一行。 使用的代码来自: 在用Obj-C编写的iOSSDK中逐行读取文件并使用NSString 查看旧版Swift的编辑历史记录。

  • 问题内容: 我正在尝试读取中给定的文件并将其加载到数组中,其中各项之间用换行符分隔。 到目前为止,这是我做的方法: 我对此不太满意,原因有两个。第一,我正在处理大小从几千字节到数百MB不等的文件。可以想象,使用如此大的字符串是缓慢且笨拙的。其次,这会在执行时冻结UI,这同样是不好的。 我已经考虑过在单独的线程中运行此代码,但是我一直在遇到麻烦,此外,它仍然不能解决处理巨大字符串的问题。 我想做的事

  • 我正在尝试读取

  • 问题内容: 我在Go中找不到功能。我可以弄清楚如何快速编写一个,但是我只是想知道我是否在这里忽略了一些东西。如何逐行读取文件? 问题答案: _注意: 可接受的答案在早期的Go版本中是正确的。 包中有ReadLine函数。 请注意,如果该行不适合读取缓冲区,则该函数将返回不完整的行。如果要始终通过单次调用函数来读取程序中的整行,则需要将该函数封装到自己的函数中,该函数在for循环中进行调用。 之所以

  • 问题内容: 下面的Mappers代码从HDFS读取文本文件正确吗?如果是这样的话: 如果不同节点中的两个映射器尝试几乎同时打开文件,会发生什么情况? 是否不需要关闭?如果是这样,如何在不关闭文件系统的情况下执行此操作? 我的代码是: 问题答案: 这将起作用,并进行一些修改-我假设您粘贴的代码被截断了: 您可以有多个映射器读取同一个文件,但是使用分布式缓存存在更多的局限性(不仅减少了承载文件块的数据

  • 我正在努力阅读附加的TXT文件,以csv形式显示从文件中读取的每个字段,我做了一个接近我想要的代码,但我没有前进。 TXT文件格式: 我的代码在我想要的位置读取第一行,但下面的行我不能,更不用说重复文件中包含的下一个工资单的读数了。 目前的输出是这样的: 出口应该是怎样的 逐行读取和捕获数据,我必须完成一个工资单,它将在输出中形成一行,第二个工资单将在输出中形成第二行,因此,直到txt文件结束,此