はじめに
ファイルパス名が指定されたら、指定されたファイルからテキストを入力、
ファイルパス名が省略されたら、標準入力からテキストを入力する。
このように動作する テキスト入力関数(その2) を作成しました。
前回記事との違いは、ファイル入力の場合は、標準入力stdin
を再割り当てすることで、以降はどちらの場合もreadLine()
としたことです。
これにより、一括入力とは違い、巨大ファイルサイズにも使用できます。
標準入力stdin
のファイルへの再割り当ては、次のとおりfreopen
するだけ。
if let _ = freopen(filepath, "r", stdin) {
while let line = readLine() {
//line 処理
}
} else {
//ファイルオープンエラー
}
テキストファイル入力 標準入力 共通関数(2)
今回は、イテレータ版のみです。
struct readTextFile: Sequence, IteratorProtocol, Sendable {
@usableFromInline
internal var eof = false
init(filepath: String?) throws {
guard let filepath else { return }
guard let _ = freopen(filepath, "r", stdin) else {
throw NSError(
domain: "MyErrorDomain",
code: Int(errno),
userInfo: [
NSLocalizedDescriptionKey: "readTextFile: \(String(cString: strerror(errno))): \(filepath)"
]
)
}
}
@inlinable
public mutating func next() -> String? {
if eof { return nil }
if let input = readLine() {
return input
}
eof = true
return nil
}
}
使い方
上記関数を呼び出す例
test.swift
import Foundation
let test: () = {
let arguments = CommandLine.arguments
let filename: String? = arguments.count > 1 ? arguments[1] : nil
do {
for line in try readTextFile(filepath: filename) {
print(line)
}
} catch {
print(error.localizedDescription)
}
}()
実行結果
% swiftc test.swift
% ./test a.txt # filepath
123
ABC
% ./test <a.txt # stdin
123
ABC
% ./test b.txt # file missing
readTextFile: No such file or directory: b.txt
ちなみに、
AtCoder でも 問題なし。
以上