-
Notifications
You must be signed in to change notification settings - Fork 0
/
StreamReader.swift
104 lines (90 loc) · 3.28 KB
/
StreamReader.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//http://stackoverflow.com/questions/24581517/read-a-file-url-line-by-line-in-swiftにあったやつ
import Foundation
public 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){
self.fileHandle = fileHandle
}else{
return nil
}
//デリミタを取得
if let delimData = delimiter.dataUsingEncoding(NSUTF8StringEncoding){
self.delimData = delimData
}else{
return nil
}
//chunkSizeバイト格納できるNSMutableData(NSDataの可変長版)を取得
if let buffer = NSMutableData(capacity:chunkSize){
self.buffer = buffer
}else{
return nil
}
}
deinit{
self.close()
}
//EOFに達したらnilを返す
func nextLine()->String?{
if atEof{
return nil
}
//NSRangeを取得(対象:デリミタ、0からbufferの長さ)
var range = buffer.rangeOfData(delimData,options:nil,range:NSMakeRange(0,buffer.length))
//構造体rangeのlocationがNSNotFound、つまりデリミタが発見されるまでやる
while range.location == NSNotFound {
//最大chunkSizeバイトのデータを読み込む
var tmpData = fileHandle.readDataOfLength(chunkSize)
if tmpData.length == 0{
//何も取得できなかったとき(EOFかエラー)
atEof = true
if buffer.length > 0{
//バッファがデータを持ってる→空にしてりたーん
let line = NSString(data:buffer,encoding:encoding);
buffer.length = 0
return line
}
//おしまい。
return nil
}
buffer.appendData(tmpData)
//もういちどNSRangeを取得そしてループ
range = buffer.rangeOfData(delimData,options:nil,range:NSMakeRange(0,buffer.length))
}
//NSRangeのながさぶん取得
let line = NSString(data: buffer.subdataWithRange(NSMakeRange(0, range.location)),
encoding: encoding)
//取得したらもういらないので消す
buffer.replaceBytesInRange(NSMakeRange(0, range.location + range.length), withBytes: nil, length: 0)
//取得したやつ返す
return line
}
//ファイルの最初から
func rewind() -> Void {
fileHandle.seekToFileOffset(0)
buffer.length = 0
atEof = false
}
//ファイルクローズ
func close() -> Void {
if fileHandle != nil {
fileHandle.closeFile()
fileHandle = nil
}
}
}
extension StreamReader : SequenceType {
public func generate() -> GeneratorOf<String> {
return GeneratorOf<String> {
return self.nextLine()
}
}
}