Working with Streams
Working with Read Streams
我们从为一个文件创建可读流开始,列表2-1,所示。
Listing 2-1 Creating a read stream from a file
CFReadStreamRef myReadStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, fileURL); |
file:///Users/joeuser/Downloads/MyApp.sit.
isting 2-2 Opening a read stream
if (!CFReadStreamOpen(myReadStream)) { |
CFStreamError myErr = CFReadStreamGetError(myReadStream); |
// An error has occurred. |
if (myErr.domain == kCFStreamErrorDomainPOSIX) { |
// Interpret myErr.error as a UNIX errno. |
} else if (myErr.domain == kCFStreamErrorDomainMacOSStatus) { |
// Interpret myErr.error as a MacOS error code. |
OSStatus macError = (OSStatus)myErr.error; |
// Check other error domains. |
} |
} |
Working with Write Streams
Listing 2-5 Creating, opening, writing to, and releasing a write stream
CFWriteStreamRef myWriteStream = |
CFWriteStreamCreateWithFile(kCFAllocatorDefault, fileURL); |
if (!CFWriteStreamOpen(myWriteStream)) { |
CFStreamError myErr = CFWriteStreamGetError(myWriteStream); |
// An error has occurred. |
if (myErr.domain == kCFStreamErrorDomainPOSIX) { |
// Interpret myErr.error as a UNIX errno. |
} else if (myErr.domain == kCFStreamErrorDomainMacOSStatus) { |
// Interpret myErr.error as a MacOS error code. |
OSStatus macError = (OSStatus)myErr.error; |
// Check other error domains. |
} |
} |
UInt8 buf[] = "Hello, world"; |
UInt32 bufLen = strlen(buf); |
| |
while (!done) { |
CFTypeRef bytesWritten = CFWriteStreamWrite(myWriteStream, buf, strlen(buf)); |
if (bytesWritten < 0) { |
CFStreamError error = CFWriteStreamGetError(myWriteStream); |
reportError(error); |
} else if (bytesWritten == 0) { |
if (CFWriteStreamGetStatus(myWriteStream) == kCFStreamStatusAtEnd) { |
done = TRUE; |
} |
} else if (bytesWritten != strlen(buf)) { |
// Determine how much has been written and adjust the buffer |
bufLen = bufLen - bytesWritten; |
memmove(buf, buf + bytesWritten, bufLen); |
| |
// Figure out what went wrong with the write stream |
CFStreamError error = CFWriteStreamGetError(myWriteStream); |
reportError(error); |
| |
} |
} |
CFWriteStreamClose(myWriteStream); |
CFRelease(myWriteStream); |
myWriteStream = NULL; |
Preventing Blocking When Working with Streams
Using Polling to Prevent Blocking
Listing 2-6 Polling a read stream
while (!done) { |
if (CFReadStreamHasBytesAvailable(myReadStream)) { |
UInt8 buf[BUFSIZE]; |
CFIndex bytesRead = CFReadStreamRead(myReadStream, buf, BUFSIZE); |
if (bytesRead < 0) { |
CFStreamError error = CFReadStreamGetError(myReadStream); |
reportError(error); |
} else if (bytesRead == 0) { |
if (CFReadStreamGetStatus(myReadStream) == kCFStreamStatusAtEnd) { |
done = TRUE; |
} |
} else { |
handleBytes(buf, bytesRead); |
} |
} else { |
// ...do something else while you wait... |
} |
} |
Listing 2-7 is a polling example for a write stream.
Listing 2-7 Polling a write stream
UInt8 buf[] = "Hello, world"; |
UInt32 bufLen = strlen(buf); |
| |
while (!done) { |
if (CFWriteStreamCanAcceptBytes(myWriteStream)) { |
int bytesWritten = CFWriteStreamWrite(myWriteStream, buf, strlen(buf)); |
if (bytesWritten < 0) { |
CFStreamError error = CFWriteStreamGetError(myWriteStream); |
reportError(error); |
} else if (bytesWritten == 0) { |
if (CFWriteStreamGetStatus(myWriteStream) == kCFStreamStatusAtEnd) |
{ |
done = TRUE; |
} |
} else if (bytesWritten != strlen(buf)) { |
// Determine how much has been written and adjust the buffer |
bufLen = bufLen - bytesWritten; |
memmove(buf, buf + bytesWritten, bufLen); |
| |
// Figure out what went wrong with the write stream |
CFStreamError error = CFWriteStreamGetError(myWriteStream); |
reportError(error); |
} |
} else { |
// ...do something else while you wait... |
} |
} |
Using a Run Loop to Prevent Blocking
This example begins by creating a socket read stream:
CFStreamCreatePairWithSocketToCFHost(kCFAllocatorDefault, host, port, |
&myReadStream, NULL); |
host, specifies the remote host with which the read stream is to be made and the port parameter specifies the port number that the host uses. The CFStreamCreatePairWithSocketToCFHostfunction returns the new read stream reference in myReadStream. The last parameter, NULL, indicates that the caller does not want to create a write stream. If you wanted to create a write steam, the last parameter would be, for example, &myWriteStream.
efore opening the socket read stream, create a context that will be used when you register to receive stream-related events:
CFStreamClientContext myContext = {0, myPtr, myRetain, myRelease, myCopyDesc}; |
copyDescription is a parameter to a function to provide a description of the stream. For example, if you were to call CFCopyDesc(myReadStream) with the stream client context shown above, CFStream would callmyCopyDesc(myPtr).
The client context also allows you the option of setting the retain, release, and copyDescription parameters toNULL. If you set the retain and release parameters to NULL, then the system will expect you to keep the memory pointed to by the info pointer alive until the stream itself is destroyed. If you set the copyDescription parameter to NULL, then the system will provide, if requested, a rudimentary description of what is in the memory pointed to by the info pointer.
With the client context set up, call the function CFReadStreamSetClient to register to receive stream-related events. CFReadStreamSetClient requires that you specify the callback function and the events you want to receive. The following example in Listing 2-8 specifies that the callback function wants to receive thekCFStreamEventHasBytesAvailable, kCFStreamEventErrorOccurred, and kCFStreamEventEndEncounteredevents. Then schedule the stream on a run loop with the CFReadStreamScheduleWithRunLoop function. SeeListing 2-8 for an example of how to do this.
Listing 2-8 Scheduling a stream on a run loop
CFOptionFlags registeredEvents = kCFStreamEventHasBytesAvailable | |
kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered; |
if (CFReadStreamSetClient(myReadStream, registeredEvents, myCallBack, &myContext) |
{ |
CFReadStreamScheduleWithRunLoop(myReadStream, CFRunLoopGetCurrent(), |
kCFRunLoopCommonModes); |
} |
With the stream scheduled on the run loop, you are ready to open the stream as shown in Listing 2-9.
Listing 2-9 Opening a nonblocking read stream
if (!CFReadStreamOpen(myReadStream)) { |
CFStreamError myErr = CFReadStreamGetError(myReadStream); |
if (myErr.error != 0) { |
// An error has occurred. |
if (myErr.domain == kCFStreamErrorDomainPOSIX) { |
// Interpret myErr.error as a UNIX errno. |
strerror(myErr.error); |
} else if (myErr.domain == kCFStreamErrorDomainMacOSStatus) { |
OSStatus macError = (OSStatus)myErr.error; |
} |
// Check other domains. |
} else |
// start the run loop |
CFRunLoopRun(); |
} |
| |
Now, wait for your callback function to be executed. In your callback function, check the event code and take appropriate action. See Listing 2-10.
本文详细介绍了如何使用CFStream框架创建、打开、读取和写入流。涵盖了错误处理、非阻塞流操作及通过runloop进行事件监听等内容。
1532

被折叠的 条评论
为什么被折叠?



