2012-11-02 26 views
9

描述: 我需要在表示要上載的文件的HTTP POST參數發送底座64編碼的字符串。大的Base64上傳

電流法:我使用ASIFormDataRequest和編碼我的文件爲Base64字符串,像這樣:

NSData *data = [[NSFileManager defaultManager] contentsAtPath:@"my path here"]; 
NSString *base64Data = [data encodeBase64ForData]; 

但是上傳大文件時,應用程序運行的內存並且死一個可怕的死亡!

建議的解決方案:現在是否有人會從磁盤讀取文件,將其轉換爲base64字符串並將轉換後的base64字符串附加到HTTP請求中的參數?

有效地避免將整個文件讀入內存的任何方式。

任何輸入將不勝感激!在全

我的http請求代碼:

NSURL *url = [NSURL URLWithString:requestProgressURLString]; 
NSData *data = [[NSFileManager defaultManager] contentsAtPath:evidence.uri]; 
NSString *base64Data = [data encodeBase64ForData]; 
NSURL *fileURL = [[NSURL alloc] initWithString:evidence.uri]; 

request = [ASIFormDataRequest requestWithURL:url]; 

request.shouldAttemptPersistentConnection = false; 
[request setShowAccurateProgress:YES]; 

[request setPostValue:accessToken forKey:@"AccessToken"]; 
[request setPostValue:[[fileURL path] lastPathComponent] forKey:@"Filename"]; 
[request setPostValue:evidence.name forKey:@"Title"]; 
[request setPostValue:base64Data forKey:@"FileData"]; //wants string value (base64 encoded)   
[request addRequestHeader:@"Content-Type" value:@"application/x-www-form-urlencoded"]; 
[request setTimeOutSeconds:60]; 
[request setUploadProgressDelegate:self]; 
[request setDownloadProgressDelegate:self]; 
[request setDelegate:self]; 
[request setDidFinishSelector:@selector(requestDone:)]; 
[request setDidFailSelector:@selector(requestWentWrong:)]; 
+0

我從來沒有見過一個分塊的Base64轉換器,但採用開源實現並將其轉換爲分塊轉換應該不會太難。 Base64並不那麼複雜。 –

+1

您是否也控制了Web服務器?意思是你可以修改那裏的代碼嗎?而當你說大文件?多大? 100 MB? 500 MB? 1 GB? –

+0

目前,上傳數量限制爲100MB,但未來可能會增加。理想情況下,解決方案應該與上傳的大小無關,因爲我確信這些代碼將用於更多的項目。目前我正在查看流... –

回答

0

而是讀取文件中的一重擊,你需要以塊的形式讀它

您可以使用輸入流來做到這一點 蘋果有一些在here

信息基本上你需要創建一個NSInputStream指着你的文件作爲例子

- (void)setUpStreamForFile:(NSString *)path { 
    // iStream is NSInputStream instance variable 
    iStream = [[NSInputStream alloc] initWithFileAtPath:path]; 
    [iStream setDelegate:self]; 
    [iStream scheduleInRunLoop:[NSRunLoop currentRunLoop] 
     forMode:NSDefaultRunLoopMode]; 
    [iStream open]; 
} 

然後可以在使用NSStreamDelegate方法 塊讀出的數據 - (無效)流:(NSStream *)流的handleEvent:(NSStreamEvent)EVENTCODE

再次蘋果得到的這個

- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode { 

    switch(eventCode) { 
     case NSStreamEventHasBytesAvailable: 
     { 
      if(!_data) { 
       _data = [[NSMutableData data] retain]; 
      } 
      uint8_t buf[1024]; 
      unsigned int len = 0; 
      len = [(NSInputStream *)stream read:buf maxLength:1024]; 
      if(len) { 
       [_data appendBytes:(const void *)buf length:len]; 
       // bytesRead is an instance variable of type NSNumber. 
       [bytesRead setIntValue:[bytesRead intValue]+len]; 

       // DO SOMETHING with DATA HERE 

      } else { 
       NSLog(@"no buffer!"); 
      } 
      break; 
     } 
一個例子

您選擇的塊大小需要是內存性能與網絡性能的平衡,因爲HTTP頭顯然會有一些開銷

您還可以通過發送您的NSData目錄進一步優化ectly(因此保存的base64開銷)檢查這個帖子

File Upload to HTTP server in iphone programming

3

我會分裂這個問題分爲兩個:在塊
2.上傳

1編碼大文件爲Base64該文件


1編碼大文件以Base64爲塊:

找到一些編碼NSData實例到Base64的代碼。然後使用一個NSInputStream來讀取塊中的數據,對其進行編碼並使用NSOutputStream寫入臨時文件。我發現這個問題/答案:Is it possible to base64-encode a file in chunks?使塊大小爲3的倍數,它應該工作。您可能希望將其移至後臺線程。

重要提示:這將創建一個臨時文件,該文件大於原始文件。那一刻,設備上必須有足夠的空間。開始上傳後,您可以將其刪除。


2.文件

上傳看來你這個已經做了。您可以使用與您的示例完全相同的ASIFormDataRequest。而且由於它會生成文件的私人副本(它構建了多部分POST文件),因此您可以刪除副本。

如果您想通過並行化這些步驟來優化它,您需要找到另一種上傳多部分文件的方法。