2013-04-15 2 views
0

Iam пытается использовать CFHTTP для записи небольшого загрузчика. К сожалению, я не могу использовать NSURL, что очень просто. Я в основном хочу асинхронный способ загрузки данных и сохранения их в файле. Я еще не нашел, как сделать асинхронный путь, но у меня есть код с подходом Sync, который не работает. Проблема заключается в том, что загрузчик не загружает полные байты. Я вижу, что некоторые данные отсутствуют, что приводит к повреждению окончательного файла. Вот код, который у меня есть.CFURL не дает полных данных при загрузке

#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; 
} 

Длина, которую я получаю, меньше, чем моя фактическая загрузка файла. Я не понимаю, что не так с этим кодом. Может кто-нибудь, пожалуйста, помогите мне с этим?

+0

Вы пробовали отлаживать. –

+0

Похоже, что Iam получает numBytesRead равным 0, который прерывает цикл. Но мой файл не завершен. – user2085689

ответ

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; 
} 

Надеюсь, это поможет. Он по-прежнему будет полезен, если кто-то может указать, что пошло не так, как исходный код.

0

Я знаю это поздно, но ваш код действительно помог мне (на удивление трудно найти прямые, полные примеры получения байтов тела ответа с использованием API CFNetworking).

В любом случае, я думаю, что ошибкой был последний параметр, должен быть FALSE (ответное сообщение), а не TRUE (сообщение запроса) в строке CFHTTPMessageCreateEmpty.

CFHTTPMessageRef cfHttpResp = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, FALSE); 
+0

Добро пожаловать. – user2085689

Смежные вопросы