Каков правильный способ отправки большого файла через HTTP POST, без загрузки всего файла в ram?
В настоящее время я работаю над приложением для загрузки больших видеофайлов с iPhone на веб-сервис через простую HTTP-почту. На данный момент я создаю NSURLRequest и предварительно загружаю все данные видеофайлов перед загрузкой запроса. Это, естественно, съедает тонну барана, если файл значительно большой, в некоторых случаях это даже не возможно.
Итак, в основном, мой вопрос: есть ли правильный способ потоковой передачи данных или загрузки его в куски без каких-либо изменений на веб-сервере?
Спасибо.
РЕДАКТИРОВАТЬ для пояснения:. Я ищу способ передачи больших данных multipart/form FROM веб-сервера iPhone TO. Не наоборот.
РЕДАКТИРОВАТЬ после принятия ответа: Я только выяснил, что у яблока есть отличный исходный код, написанный для этой конкретной цели, и он показывает добавление дополнительных данных к сообщению не только самому большому файлу. Если кому-то это понадобится: SimpleURLConnections - PostController.m
Еще один EDIT: При использовании этого фрагмента исходного кода из Apple я столкнулся с очень тупой и уродливой проблемой, которая даже wirehark не могла" t помогите мне отлаживать. Некоторые веб-серверы не понимают пограничную строку, когда она объявляется между кавычками (например, в примере яблок). У меня были проблемы с ним на Apache Tomcat, и удаление котировок работало просто замечательно.
Ответы
Ответ 1
Вы можете использовать NSInputStream
в NSMutableURLRequest
. Например:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:uploadURL];
NSInputStream *stream = [[NSInputStream alloc] initWithFileAtPath:filePath];
[request setHTTPBodyStream:stream];
[request setHTTPMethod:@"POST"];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSLog(@"Finished with status code: %i", [(NSHTTPURLResponse *)response statusCode]);
}];
Ответ 2
Вы можете использовать NSInputStream
, чтобы предоставить данные для отправки через -[NSMutableURLRequest setHTTPBodyStream:]
. Это может быть поток ввода, который читается из файла. Возможно, вам понадобится реализовать метод connection:needNewBodyStream:
в вашем делете соединения с URL, чтобы предоставить новый, нераскрытый поток, если система должна повторно передать данные.
Ответ 3
Один из способов сделать это - использовать асинхронный NSInputStream совместно с файлом. Когда асинхронное соединение просит вас предоставить больше данных, вы читаете данные из файла. У вас есть несколько способов сделать это:
-
Интерфейс UNIX/BSD. использовать open (или fopen), malloc, читать и создавать объект NSData из malloced datap >
-
используйте приведенное выше с помощью mmap(), если вы знаете его
-
используйте API-интерфейс NSFileHandle класса Foundation, чтобы сделать более или менее то же самое с помощью ObjectiveC
Вы можете читать потоки в "Руководстве по программированию потоков". Если это не работает для вас, есть много проектов с открытым исходным кодом, которые могут загружать файлы, например MKNetworkKit