CFURL在下载时不提供完整数据

时间:2013-04-15 01:58:29

标签: objective-c c macos core-foundation

Iam尝试使用CFHTTP编写一个小型下载程序。不幸的是我不能使用非常简单的NSURL。我基本上想要一种异步方式来下载数据并将其存储在一个文件中。我还没有找到如何做异步方式,但我有一些代码与Sync方法不一样。问题是下载器没有下载完整的字节。我看到一些数据丢失导致最终文件损坏。这是我到目前为止的代码。

#include <stdio.h>
#include <string.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CFNetwork/CFNetwork.h>
#include <CFNetwork/CFHTTPStream.h>

int main(int argc, const char * argv[])
{

    // insert code here...
    const char *data;
    FILE *fp;
    CFShow(CFSTR("Hello, World!\n"));

    CFURLRef cfUrl = CFURLCreateWithString(kCFAllocatorDefault, CFSTR("http://the.earth.li/~sgtatham/putty/0.62/x86/putty.zip"), NULL);
    CFHTTPMessageRef cfHttpReq = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), cfUrl, kCFHTTPVersion1_1);

    CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, cfHttpReq);
    CFReadStreamOpen(readStream);

    CFHTTPMessageRef cfHttpResp = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, TRUE);
    CFIndex numBytesRead;

    do {
        const int nBuffSize = 1024;
        UInt8 buff[nBuffSize];
        numBytesRead = CFReadStreamRead(readStream, buff, nBuffSize);
        if( numBytesRead > 0 )
        {
            CFHTTPMessageAppendBytes(cfHttpResp, buff, numBytesRead);
        }
        else if( numBytesRead < 0 )
        {
            CFStreamError error = CFReadStreamGetError(readStream);
            printf ("Error %d", error.error);
        }
    } while ( numBytesRead > 0 );
    CFStringRef myStatusLine = CFHTTPMessageCopyResponseStatusLine(cfHttpReq);
    CFReadStreamClose(readStream);
    CFDataRef cfResp = CFHTTPMessageCopyBody(cfHttpResp);
    CFIndex length = CFDataGetLength(cfResp);
    printf ("%lu\n", length);
    CFShow(myStatusLine);
    data = (const char*)CFDataGetBytePtr(cfResp);
    fp = fopen("/var/tmp/Update.zip", "w");
    if (fp == NULL) {
        printf("ACnnot be opened\n");
    } else {
        fwrite(data, length, 1, fp);
        fclose(fp);
    }
    printf ("Download done\n");
    CFRelease(cfUrl);
    CFRelease(cfHttpReq);
    CFRelease(readStream);
    CFRelease(cfHttpResp);
    CFRelease(cfResp);

    return 0;
}

我得到的长度小于我的实际文件下载量。我不明白这段代码有什么问题。有人可以帮我这个吗?

2 个答案:

答案 0 :(得分:1)

我还不知道这段代码出了什么问题。但我通过替换

解决了我的问题

// CFHTTPMessageRef cfHttpResp = CFHTTPMessageCreateEmpty(kCFAllocatorDefault,TRUE);     CFMutableDataRef cfResp = CFDataCreateMutable(kCFAllocatorDefault,0); 我现在使用MutableDataRef而不是CFHTTPMessageRef。我将在这里更新新代码。

int main(int argc, const char * argv[])
{

    // insert code here...
    const char *data;
    FILE *fp;
    CFShow(CFSTR("Hello, World!\n"));

    CFURLRef cfUrl = CFURLCreateWithString(kCFAllocatorDefault, CFSTR("http://the.earth.li/~sgtatham/putty/0.62/x86/putty.zip"), NULL);
    CFHTTPMessageRef cfHttpReq = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), cfUrl, kCFHTTPVersion1_1);

    CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, cfHttpReq);
    CFReadStreamOpen(readStream);

    //CFHTTPMessageRef cfHttpResp = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, TRUE);
    CFMutableDataRef cfResp = CFDataCreateMutable(kCFAllocatorDefault, 0);
    CFIndex numBytesRead;

    do {
        const int nBuffSize = 1024;
        UInt8 buff[nBuffSize];
        numBytesRead = CFReadStreamRead(readStream, buff, nBuffSize);
        if( numBytesRead > 0 )
        {
            CFDataAppendBytes(cfResp, buff, numBytesRead);
            //CFHTTPMessageAppendBytes(cfHttpResp, buff, numBytesRead);
        }
        else if( numBytesRead < 0 )
        {
            CFStreamError error = CFReadStreamGetError(readStream);
            printf ("Error %d", error.error);
        }
    } while ( numBytesRead > 0 );

    CFReadStreamClose(readStream);
    //CFDataRef cfResp = CFHTTPMessageCopyBody(cfHttpResp);
    CFIndex length = CFDataGetLength(cfResp);
    printf ("%lu\n", length);

    data = (const char*)CFDataGetBytePtr(cfResp);
    fp = fopen("/var/tmp/Update.zip", "w");
    if (fp == NULL) {
        printf("ACnnot be opened\n");
    } else {
        fwrite(data, length, 1, fp);
        fclose(fp);
    }
    printf ("Download done\n");
    CFRelease(cfUrl);
    CFRelease(cfHttpReq);
    CFRelease(readStream);
    CFRelease(cfResp);

    return 0;
}

希望这会有所帮助。如果有人能够指出原始代码出了什么问题,它仍然会很有用。

答案 1 :(得分:0)

我知道这件事已经很晚了,但是你的代码确实帮助了我(很难找到使用CFNetworking API获取响应正文字节的直接,完整的示例)。

无论如何,我认为错误是最后一个参数应该是FALSE(响应消息),而不是CFHTTPMessageCreateEmpty行中的TRUE(请求消息)。

CFHTTPMessageRef cfHttpResp = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, FALSE);