[swift-users] file io in Swift 2.2 for Linux (would like to be pointed in the right direction)
Matthias Zenger
matthias at objecthub.net
Sun Jun 5 16:04:28 CDT 2016
Quinn, Jens, thanks for pointing me at the NSStream classes. For some
reason, I discarded NSStream quickly after seeing the first paragraph
of Apple's
documentation on output streams
<https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Streams/Articles/WritingOutputStreams.html>
listing 5 relatively complex steps — without realizing that this API also
has a synchronous interface.
Obviously, the NSStream API is too low level and thus difficult to use.
Therefore, I would also like to see Apple build a great IO streaming API
for Swift. I've implemented Quinn's example using NSInputStream and Swift's
Generator design pattern. Except for mapping NSInputStream to a generator —
which is really messy — everything else is straightforward and much more
extensible and scalable than the standard Foundation approach. The code is
below.
== Matthias
See https://gist.github.com/objecthub/ada1f852924b2c253653d6949fd3555d
class ByteGenerator: GeneratorType {
typealias Element = UInt8
let input: NSInputStream
var buffer: [UInt8]
var index: Int = 0
var eof: Bool = true
init?(path: String, capacity: Int = 1024) {
guard let input = NSInputStream(fileAtPath: path) else {
return nil
}
self.buffer = [UInt8](count: capacity, repeatedValue: 0)
input.open()
if input.hasBytesAvailable {
self.eof = input.read(&self.buffer, maxLength: self.buffer.count *
sizeof(UInt8)) <= 0
}
self.input = input
}
deinit {
input.close()
}
func next() -> UInt8? {
guard !self.eof else {
return nil
}
if self.index >= self.buffer.count {
self.index = 0
self.eof = !input.hasBytesAvailable ||
input.read(&self.buffer, maxLength: self.buffer.count *
sizeof(UInt8)) <= 0
guard !self.eof else {
return nil
}
}
self.index += 1
return self.buffer[self.index - 1]
}
}
struct CharacterGenerator<G: GeneratorType, U: UnicodeCodecType where
G.Element == U.CodeUnit>: GeneratorType {
typealias Element = Character
var source: G
var decoder: U
mutating func next() -> Character? {
guard case .Result(let scalar) = self.decoder.decode(&self.source) else
{
return nil
}
return Character(scalar)
}
}
struct LineGenerator<G: GeneratorType where G.Element == Character>:
GeneratorType {
typealias Element = String
var source: G
mutating func next() -> String? {
guard let fst = source.next() else {
return nil
}
guard fst != "\n" else {
return ""
}
var line = String(fst)
while let ch = source.next() {
if (ch == "\n") {
return line
}
line.append(ch)
}
return line
}
}
if let input = ByteGenerator(path: "/Users/username/filename.txt") {
var generator = LineGenerator(source: CharacterGenerator(source: input,
decoder: UTF8()))
var i = 0
while let line = generator.next() {
print("\(i): \(line)")
i += 1
}
}
*Matthias Zenger* matthias at objecthub.net
On Sun, Jun 5, 2016 at 8:36 PM, Jens Alfke <jens at mooseyard.com> wrote:
>
> On Jun 4, 2016, at 6:25 PM, Matthias Zenger via swift-users <
> swift-users at swift.org> wrote:
>
> I wanted to use NSFileHandle (for a use case that requires streaming) and
> realized that this is an API that cannot really be used in Swift because
> it's based on Objective-C exceptions.
>
>
> You’re right, NSFileHandle is a very archaic class (kind of a coelacanth)
> and its I/O methods signal errors by throwing exceptions. It’s almost
> unique in that regard; in general Cocoa APIs are only supposed to throw
> exceptions for programmer errors like assertion failures.
>
> Are there any alternatives?
>
>
> NSStream.
>
> —Jens
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20160605/f4cc73fd/attachment.html>
More information about the swift-users
mailing list