Skip to content

Instantly share code, notes, and snippets.

@reitzig
Last active April 15, 2022 03:47
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save reitzig/29d38b948812454a8dedc00a9f61f44f to your computer and use it in GitHub Desktop.
Save reitzig/29d38b948812454a8dedc00a9f61f44f to your computer and use it in GitHub Desktop.
Reading InputStream into Data
extension Data {
/**
Consumes the specified input stream, creating a new Data object
with its content.
- Parameter reading: The input stream to read data from.
- Note: Closes the specified stream.
*/
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)
self.append(buffer, count: read)
}
buffer.deallocate()
input.close()
}
/**
Consumes the specified input stream for up to `byteCount` bytes,
creating a new Data object with its content.
- Parameter reading: The input stream to read data from.
- Parameter byteCount: The maximum number of bytes to read from `reading`.
- Note: Does _not_ close the specified stream.
*/
init(reading input: InputStream, for byteCount: Int) {
self.init()
input.open()
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: byteCount)
let read = input.read(buffer, maxLength: byteCount)
self.append(buffer, count: read)
buffer.deallocate()
}
}
import Foundation
import XCTest
class DataTests: XCTestCase {
func testInitFromStream() {
// Tests some random values, plus the empty case
[[UInt8](),
[0b00001001],
[0b01000000, 0b01001011],
[0b01011110, 0b11101111, 0b00011001],
[0b01101100, 0b00101010, 0b10111001, 0b10000111],
[0b00011011, 0b00010111, 0b00011000, 0b01100100, 0b10110000],
[UInt8](repeating: 77, count: 2049) // something large; 2*buffersize + 1
].forEach { (bytes) in
let referenceData = Data(bytes)
let stream = InputStream(data: referenceData)
XCTAssertEqual(Data(reading: stream), referenceData)
}
}
func testInitFromStreamWithMaxLength() {
// Tests some random values, plus the empty case
[[UInt8](),
[0b00001001],
[0b01000000, 0b01001011],
[0b01011110, 0b11101111, 0b00011001],
[0b01101100, 0b00101010, 0b10111001, 0b10000111]
].forEach { (bytes) in
let referenceData = Data(bytes)
let stream = InputStream(data: referenceData)
defer { stream.close() }
XCTAssertEqual(
Data(reading: stream, for: 3),
referenceData[0..<(min(3, referenceData.count))]
)
}
}
}
@princesslyons
Copy link

princesslyons commented May 1, 2017

Does buffer.deallocate() clear/flush the buffer? Below is an example of the function I have that needs to read from the stream. The stream is receiving data every 1 or 2 seconds. The data is an integer data type. However, if I don't read from the stream after each update, the buffer is overwritten. I am working on a project and can't seem to find an efficient way to simply clear the buffer after each read.

` // Function: readMessage - read a message from the stream (1 integer value)

func readMessage() -> String{
    var buffer = [UInt8](repeating: 0, count: 5)
    let nBytes: Int = inStream!.read(&buffer, maxLength: buffer.count)              //Read from inStream into buffer
    let bufferStr = NSString(bytes: &buffer, length: nBytes, encoding: String.Encoding.utf8.rawValue)
    print("Read: " + (bufferStr! as String))
    return (bufferStr! as String)

}`

@reitzig
Copy link
Author

reitzig commented Aug 31, 2017

Sorry, I completely missed your comment! Do we not get notifications here?

Did you solve the issue? I'm not sure I understand fully what the problem is; I'd recommend you open a question on Stack Overflow!

That said, I don't think the function I've written is suitable for reading from streams that are "slow". At least I never tried it on such.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment