Как определить размер (в байтах) загружаемого файла с помощью NSURLConnection?
-
18-09-2019 - |
Вопрос
Мне нужно знать размер файла, который я загружаю (в байтах) в свое приложение, используя NSURLConnection (GET).Вот мой полученный байтами код ниже, если это поможет.Что мне нужно знать, так это как получить размер файла в байтах, чтобы я мог использовать его для отображения UIProgressView.
- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)data
// A delegate method called by the NSURLConnection as data arrives. We just
// write the data to the file.
{
#pragma unused(theConnection)
NSInteger dataLength;
const uint8_t * dataBytes;
NSInteger bytesWritten;
NSInteger bytesWrittenSoFar;
assert(theConnection == self.connection);
dataLength = [data length];
dataBytes = [data bytes];
bytesWrittenSoFar = 0;
do {
bytesWritten = [self.fileStream write:&dataBytes[bytesWrittenSoFar] maxLength:dataLength - bytesWrittenSoFar];
assert(bytesWritten != 0);
if (bytesWritten == -1) {
[self _stopReceiveWithStatus:@"File write error"];
break;
} else {
bytesWrittenSoFar += bytesWritten;
} while (bytesWrittenSoFar != dataLength);
}
Решение
[длина данных] возвращает размер данных в байтах, который должен дать вам цифру, которую вы ищете.
Но NSData предоставляет -writeToFile:атомарно:и -writeToFile: параметры: ошибка методов записи данных на диск, поэтому я не знаю, почему вы пишете свой собственный файл ввода-вывода.
Другие советы
Я полагаю, что код взят из примера кода SimpleURLConnections от Apple.Вот прямая цитата из метода NSURLConnection от Apple "connection:didReceiveData:"
"Делегат должен объединить содержимое каждого доставленного объекта данных для создания полных данных для загрузки URL".
NSData не предоставляет методов для постепенной записи в файл, он записывает все это сразу, поэтому я думаю, что этот метод постепенной записи в NSOutputStream, здесь называемый FileStream, является правильным.Использование dataLength в этом коде вернет только длину данных, которые были отправлены из NSURLConnection делегату в одном вызове "connection:didReceiveData:", а не общую длину данных для всего соединения.Чтобы достичь этого, я добавил дополнительные свойства:
@property (nonatomic, assign) long long dataWrittenForWholeConnection;
@property (nonatomic, assign) long long dataLengthOfWholeConnection;
В связи: Получил ли ответ:Я использовал метод NSURLResponse expectedContentLength, чтобы получить правильную оценку размера файла получаемых данных для всего соединения.
self.dataWrittenForWholeConnection = 0;
self.dataLengthOfWholeConnection = [httpResponse expectedContentLength];
В связи:didReceiveData:Я изменил следующее:
// bytes written for current "connection:didReceiveData:" call
bytesWrittenSoFar += bytesWritten;
// cumulative data written for connection so far
self.dataWrittenForWholeConnection += bytesWritten;
// also update the progress bar
if (self.dataLengthOfWholeConnection != NSURLResponseUnknownLength) {
self.progressView.progress =
((float)self.dataWrittenForWholeConnection / (float)self.dataLengthOfWholeConnection);
}
К концу подключения это должно быть правдой:
assert(dataWrittenForWholeConnection == dataLengthOfWholeConnection);
Вот распечатка из того же кода SimpleURLConnections с моими изменениями, чтобы показать, что происходит на самом деле:
connection:didReceiveResponse:
Full size of data is 8789 bytes
connection:didReceiveData:
Data has 1408 bytes
Progress bar is at: 0.160200
1408 bytes of data were written, 1408 bytes so far
connection:didReceiveData:
Data has 1408 bytes
Progress bar is at: 0.320401
1408 bytes of data were written, 2816 bytes so far
connection:didReceiveData:
Data has 1408 bytes
Progress bar is at: 0.480601
1408 bytes of data were written, 4224 bytes so far
connection:didReceiveData:
Data has 1408 bytes
Progress bar is at: 0.640801
1408 bytes of data were written, 5632 bytes so far
connection:didReceiveData:
Data has 1408 bytes
Progress bar is at: 0.801001
1408 bytes of data were written, 7040 bytes so far
connection:didReceiveData:
Data has 1749 bytes
Progress bar is at: 1.000000
1749 bytes of data were written, 8789 bytes so far
connectionDidFinishLoading:
Connection Finished. 8789/8789 bytes of data were written.
Кроме того, метод NSOutputStream "write:maxLength:" возвращает "количество фактически записанных байт", поэтому по какой-то причине он может предпочесть не записывать все данные сразу в рамках одного вызова "connection:didReceiveData:", поэтому для проверки этого используется цикл do / while.Но в этом примере он записывает все данные за одну итерацию do / while.
Кроме того, вы можете использовать вместо этого NSFileHandle , и это всегда будет записывать все данные, отправляемые при каждом соединении:didReceiveData:вызов, также это инкрементный.Обратите внимание, однако, что writeData:является синхронным.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// write data to file handler
unsigned long long dataLength = [data length];
NSLog(@"Writing %qu bytes at %qu bytes", dataLength, [self.fileHandle offsetInFile]);
[self.fileHandle writeData:data];
NSLog(@"Wrote %qu bytes, now at %qu bytes", dataLength, [self.fileHandle offsetInFile]);
}