9

In Swift 3.x, we usually handle binary data using Data; from it you can generate most other important types, and there are useful functions on it.

But how do I create a Data from an InputStream? Is there a nice way?

Raphael
  • 9,779
  • 5
  • 63
  • 94

2 Answers2

23

I could not find a nice way. We can create a nice-ish wrapper around the unsafe stuff:

extension Data {
    init(reading input: InputStream) throws {
        self.init()
        input.open()
        defer {
            input.close()
        }

        let bufferSize = 1024
        let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
        defer {
            buffer.deallocate()
        }
        while input.hasBytesAvailable {
            let read = input.read(buffer, maxLength: bufferSize)
            if read < 0 {
                //Stream error occured
                throw input.streamError!
            } else if read == 0 {
                //EOF
                break
            }
            self.append(buffer, count: read)
        }
    }
}

This is for Swift 5. Find full code with test (and a variant that reads only some of the stream) here.

Werner Altewischer
  • 10,080
  • 4
  • 53
  • 60
Raphael
  • 9,779
  • 5
  • 63
  • 94
1

above the code, It can be infinite loop. When I convert httpbodyInpustream to data, it happend. So I add a condition.

extension Data {
    init(reading input: InputStream) {
        self.init()
        input.open()

        let bufferSize = 1024
        let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
        while input.hasBytesAvailable {
            let read = input.read(buffer, maxLength: bufferSize)
            if (read == 0) {
                break  // added
            }
            self.append(buffer, count: read)
        }
        buffer.deallocate(capacity: bufferSize)

        input.close()
    }
}
Pang
  • 9,564
  • 146
  • 81
  • 122
nelsonK
  • 21
  • 4
  • Sounds like that stream is broken; `hasBytesAvailable` should return `false`, shouldn't it? Not sure what the semantics of `hasBytesAvailable == true` but `read == 0` is; sounds like an error scenario to me. – Raphael May 18 '17 at 05:34
  • @Raphael `InputStream.read(_ buffer: UnsafeMutablePointer, maxLength len: Int) -> Int` returns `-1` if there was an error, `0` if there's no more to read, and `>1` if there are bytes left to read. – Andreas is moving to Codidact Jan 10 '18 at 14:39
  • 5
    hasBytesAvailable is allowed to return true if a read has to be performed to actually check whether bytes are available (read the NSInputStream documentation). A proper implementation has to check the read result code. I modified the accepted answer with correct error handling. – Werner Altewischer Jul 05 '19 at 11:05