1

おはようございます。いくつかのファイルをアップロードするアプリケーションを開発しています。実際の問題はありませんが、大きな問題が 1 つだけあります。1 GB のファイルをアップロードしようとすると、1 GB のメモリが割り当てられます。これは良いことではありません。

これが私のコードです: データを NSData として割り当て、NSMutableURLRequest + NSURLConnection を使用してそれらをアップロードします。私の質問は: メモリ全体を割り当てる必要なくこれを行う方法はありますか? 調べたけど何も出てこなかった…

_uploadDataFile は、以前に割り当てられた NSData サブクラス インスタンスです。

NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://my.server/page"]
                                                            cachePolicy:NSURLRequestReloadIgnoringCacheData
                                                        timeoutInterval:60.0] autorelease];

NSData *dataFile;

if (_uploadDataFile == nil) {
    NSError *error = nil;
    dataFile = [[[NSData alloc] initWithContentsOfFile:@"pathToFile" options:NSDataReadingUncached error:&error] autorelease];

    if (error) {
        NSLog(@"Error %i: %@", [error code], [error localizedDescription]);
        [self fermaUpload]; //Stop Upload
        return;
    }
}

else 
    dataFile = [_uploadDataFile file];

NSMutableDictionary *dictPost = [[[NSMutableDictionary alloc] init] autorelease];
[dictPost setValue:dataFile forKey:@"uploads[]"];

NSData *mutData = [self dataForPOSTWithDictionary:dictPost boundary:@"0194784892923" nomeFile:[@"pathToFile" lastPathComponent]];

NSString *postLength = [NSString stringWithFormat:@"%d", [mutData length]];

[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"multipart/form-data; boundary=0194784892923" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:mutData];
[request setHTTPShouldHandleCookies:YES];

theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

方法は次のとおりです - (NSData *)dataForPOSTWithDictionary:boundary:nomeFile: メソッドは次のようになります。

- (NSData *)dataForPOSTWithDictionary:(NSDictionary *)aDictionary boundary:(NSString *)aBoundary nomeFile:(NSString *)nomeFile {
NSArray *myDictKeys = [aDictionary allKeys];
NSMutableData *myData = [NSMutableData dataWithCapacity:1];
NSString *myBoundary = [NSString stringWithFormat:@"--%@\r\n", aBoundary];

for(int i = 0;i < [myDictKeys count];i++) {
    id myValue = [aDictionary valueForKey:[myDictKeys objectAtIndex:i]];
    [myData appendData:[myBoundary dataUsingEncoding:NSUTF8StringEncoding]];
    //if ([myValue class] == [NSString class]) {
    if ([myValue isKindOfClass:[NSString class]]) {
        [myData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", [myDictKeys objectAtIndex:i]] dataUsingEncoding:NSUTF8StringEncoding]];
        [myData appendData:[[NSString stringWithFormat:@"%@", myValue] dataUsingEncoding:NSUTF8StringEncoding]];
    } else if(([myValue isKindOfClass:[NSURL class]]) && ([myValue isFileURL])) {
        [myData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", [myDictKeys objectAtIndex:i], [[myValue path] lastPathComponent]] dataUsingEncoding:NSUTF8StringEncoding]];
        [myData appendData:[[NSString stringWithFormat:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
        [myData appendData:[NSData dataWithContentsOfFile:[myValue path]]];
    } else if(([myValue isKindOfClass:[NSData class]])) {
        [myData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", [myDictKeys objectAtIndex:i], nomeFile] dataUsingEncoding:NSUTF8StringEncoding]];
        [myData appendData:[[NSString stringWithFormat:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
        [myData appendData:myValue];
    } // eof if()

    [myData appendData:[[NSString stringWithString:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
} // eof for()
[myData appendData:[[NSString stringWithFormat:@"--%@--\r\n", aBoundary] dataUsingEncoding:NSUTF8StringEncoding]];

return myData; } // eof dataForPOSTWithDictionary:boundary:

ありがとう、そして私の英語でごめんなさい。

4

1 に答える 1

3

非常に興味深い問題です。ボディ データを にフィードするには、次の 2 つの方法がありますNSURLConnection/Request

  • NSData
  • NSInputStream

残念ながら、ファイルといくつかのフォーム データをアップロードする必要があるため、すぐに使用できるものはありません。理想的には、サブクラス化NSInputStreamして、必要に応じてフォーマットされたデータを提供できます。ただし、最後に確認したときは、NSURLConnectionそのようなサブクラスを処理できませんでした。代わりに、次のようにします。

  1. を使用してストリームのペアを作成しますCFStreamCreateBoundPair()CFWriteStreamこれにより、およびが返されます。これらは、それぞれおよびにCFReadStream無料でブリッジされています。NSOutputStreamNSInputStream
  2. 出力ストリームのデリゲートとして自分自身を設定します
  3. -setHTTPBodyStream:入力ストリームを使用した URL リクエスト
  4. 接続を開始する

出力ストリームのデリゲートが定期的に呼び出され、データを要求するようになりました。POST データをフィードし、その後にファイル データのチャンクをフィードする必要があります。したがって、ファイル全体が一度に完全にメモリ内にあることはありません。

于 2011-10-19T10:59:40.470 に答える