簡體   English   中英

使用NsurlConnection下載大型base64編碼的數據

[英]Downloading large base64encoded data using NsurlConnection

我正在嘗試使用POST請求從服務器下載大文件。 該文件作為base64Encoded數據接收。 文件大小超過400Mb。 我使用的第一種方法是將在didReceiveData中接收到的數據附加到然后在connectionDidFinishLoading中用於解碼數據並將數據寫入文檔目錄中的文件。 此方法適用於小文件。 但是由於文件大小很大(400MB)而崩潰。 然后,當接收到數據時,我使用NSFileHandle的方法將文件分塊寫入。 我使用了3MB的塊來寫入數據。 對於小於3MB的文件,直接從base64解碼接收到的數據,並成功創建文件。 但是,當文件大小大於3MB時,我嘗試使用“ initWithBase64EncodedData:Options ”從base64解碼塊數據,得到的數據為零。 想知道我在代碼中做錯了什么。

- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
{
    receivedData = [[NSMutableData alloc] init];

    NSString* folderPath = [NSHomeDirectory() stringByAppendingPathComponent:@"/Documents/UserDocs"];
    if(![[NSFileManager defaultManager]  fileExistsAtPath:folderPath]) {
        [[NSFileManager defaultManager] createDirectoryAtPath:folderPath withIntermediateDirectories:NO attributes:nil error:nil];
   }

NSString *strFilePath = [folderPath stringByAppendingPathComponent:strFileName];    NSString *newFilePath = [NSString stringWithFormat:@"%@.%@", strFilePath, strFileExtension];
if(![[NSFileManager defaultManager]  fileExistsAtPath:newFilePath]) {
          [[NSFileManager defaultManager] createFileAtPath:newFilePath contents:nil attributes:nil];
        }

self.fileHandle = [[NSFileHandle fileHandleForWritingAtPath:newFilePath] retain];
        [self.fileHandle seekToFileOffset:0];
}

- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
{
    [receivedData appendData:data];
    NSUInteger chunkSize = 300000;
    if( receivedData.length > chunkSize  && self.fileHandle!=nil) {

        NSData *chunk = [receivedData subdataWithRange:NSMakeRange(0, chunkSize)];
        NSData *writableData = [[NSData alloc] initWithBase64EncodedData:chunk options:NSDataBase64DecodingIgnoreUnknownCharacters];
       [receivedData replaceBytesInRange:NSMakeRange(0, chunkSize) withBytes:NULL length:0];

       [self.fileHandle seekToEndOfFile];
       [self.fileHandle writeData:writableData];
       [writableData release];
    }
}

- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
    if (receivedData)
    {
        NSData *writableData = [[NSData alloc] initWithBase64EncodedData:receivedData options:NSDataBase64DecodingIgnoreUnknownCharacters];
        [receivedData release];

        [self.fileHandle seekToEndOfFile];
        [self.fileHandle writeData:writableData];
        [writableData release];

        NSLog(@"File Write Success!!");
    }
}

兩種可能的方法:

  1. 跳過base64編碼(如果可以)。
  2. 在獲取數據時將其寫入磁盤,然后使用內存映射將文件映射到RAM中,就可以像在內存中一樣在其中使用它,但實際上不占用內存。

基本上:

#include <sys/stat.h>
#include <sys/mman.h>
...
NSURL *url = // path to file on disk
char *path = [url fileSystemRepresentation];
struct stat buf;

// Round up to an exact multiple of the page size
NSUInteger size = (buf.st_size + PAGE_MASK) & ~PAGE_MASK;
NSData *data = nil;

if (!stat(path, &buf)) {
    int fd = open(path, O_RDONLY);
    if (fd != -1) {
        mmap(NULL, size, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0);
        data = [NSData dataWithBytesNoCopy:buf length:buf.st_size];
    }
}

// Perform a base64 decode on the NSData object and hope that
// at least the result will fit in RAM.

// Clean up.
data = nil;
if (!stat(path, &buf)) {
    int fd = open(path, O_RDONLY);
    if (fd != -1) {
        munmap(addr, size);
    }
}

剩下的工作就是創建一個base64解碼器,該解碼器可以將數據直接寫到磁盤上的文件中,作為讀者的一項練習。 :-)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM