Как определить размер (в байтах) загрузки файла с помощью NSURLConnection? - PullRequest
4 голосов
/ 05 февраля 2010

Мне нужно знать размер файла, который я загружаю (в байтах) в мое приложение, используя 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);
}

Ответы [ 2 ]

2 голосов
/ 05 февраля 2010

[длина данных] возвращает размер данных в байтах, который должен дать вам искомое число.

Но NSData предоставляет -writeToFile: atomically: и -writeToFile: options: методы ошибок при записи данных на диск, поэтому я не знаю, почему вы пишете свой собственный файловый ввод / вывод.

1 голос
/ 16 января 2011

Я считаю, что код взят из примера кода 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;

В связи: didReceiveResponse: Я использовал метод NSURLResponse Ожидаемый размер содержимого для получения правильной оценки размера файла принимаемых данных для всего соединения.

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: call, также оно является инкрементным. Обратите внимание, что 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]);
}
...