@@ -35,27 +35,46 @@ package struct AsyncBufferedFileSequence: AsyncBufferedSequence {
35
35
package typealias Element = UInt8
36
36
37
37
private let fileURL : URL
38
+ private let range : Range < Int >
38
39
39
- package init ( contentsOf fileURL: URL ) {
40
+ package let fileSize : Int
41
+ package var count : Int { range. count }
42
+
43
+ package init ( contentsOf fileURL: URL , range: Range < Int > ? = nil ) throws {
40
44
self . fileURL = fileURL
45
+ self . fileSize = try Self . fileSize ( at: fileURL)
46
+
47
+ if let range {
48
+ self . range = range
49
+ guard range. lowerBound >= 0 , range. upperBound <= fileSize else {
50
+ throw FileSizeError ( " Invalid range \( range) for file size \( fileSize) " )
51
+ }
52
+ } else {
53
+ self . range = 0 ..< fileSize
54
+ }
41
55
}
42
56
43
57
package func makeAsyncIterator( ) -> Iterator {
44
- Iterator ( fileURL: fileURL)
58
+ Iterator ( fileURL: fileURL, range : range )
45
59
}
46
60
47
61
package struct Iterator : AsyncBufferedIteratorProtocol {
48
62
49
63
private let fileURL : URL
64
+ private let range : Range < Int >
50
65
private var fileHandle : FileHandle ?
66
+ private var offset : Int = 0
51
67
52
- init ( fileURL: URL ) {
68
+ init ( fileURL: URL , range : Range < Int > ) {
53
69
self . fileURL = fileURL
70
+ self . range = range
71
+ self . offset = range. lowerBound
54
72
}
55
73
56
74
private mutating func makeOrGetFileHandle( ) throws -> FileHandle {
57
75
guard let fileHandle else {
58
76
let handle = try FileHandle ( forReadingFrom: fileURL)
77
+ try handle. seek ( toOffset: UInt64 ( offset) )
59
78
self . fileHandle = handle
60
79
return handle
61
80
}
@@ -67,7 +86,16 @@ package struct AsyncBufferedFileSequence: AsyncBufferedSequence {
67
86
}
68
87
69
88
package mutating func nextBuffer( suggested count: Int ) async throws -> Data ? {
70
- try makeOrGetFileHandle ( ) . read ( suggestedCount: count)
89
+ let endIndex = Swift . min ( offset + count, range. upperBound)
90
+ guard endIndex <= range. upperBound else {
91
+ return nil
92
+ }
93
+ guard let data = try makeOrGetFileHandle ( ) . read ( suggestedCount: endIndex - offset) else {
94
+ return nil
95
+ }
96
+
97
+ offset += data. count
98
+ return data
71
99
}
72
100
}
73
101
}
@@ -85,20 +113,24 @@ extension FileHandle {
85
113
}
86
114
}
87
115
88
- package extension AsyncBufferedFileSequence {
116
+ extension AsyncBufferedFileSequence {
89
117
90
- static func fileSize( at url: URL ) throws -> Int {
118
+ package static func fileSize( at url: URL ) throws -> Int {
91
119
try fileSize ( from: FileManager . default. attributesOfItem ( atPath: url. path) )
92
120
}
93
121
94
- internal static func fileSize( from att: [ FileAttributeKey : Any ] ) throws -> Int {
122
+ static func fileSize( from att: [ FileAttributeKey : Any ] ) throws -> Int {
95
123
guard let size = att [ . size] as? UInt64 else {
96
- throw FileSizeError ( )
124
+ throw FileSizeError ( " File size not found " )
97
125
}
98
126
return Int ( size)
99
127
}
100
128
101
- internal struct FileSizeError : LocalizedError {
102
- package var errorDescription : String ? = " File size not found "
129
+ struct FileSizeError : LocalizedError {
130
+ package var errorDescription : String ?
131
+
132
+ init ( _ message: String ) {
133
+ self . errorDescription = message
134
+ }
103
135
}
104
136
}
0 commit comments