How to determine the size (in bytes) of a file downloading using NSURLConnection?

人走茶凉 提交于 2019-12-05 13:30:07

[data length] does return the size of the data in bytes which should give you the figure you're looking for.

But NSData provides -writeToFile:atomically: and -writeToFile:options:error methods for writing data to disk so I don't know why you're writing your own file I/O.

I believe the code is from the SimpleURLConnections sample code from Apple. Here is a direct quote from Apple's NSURLConnection method "connection:didReceiveData:"

"The delegate should concatenate the contents of each data object delivered to build up the complete data for a URL load."

NSData does not provide methods to write incrementally to a file, it writes it all at once, so I think this method of writing incrementally to an NSOutputStream, here named fileStream, is correct. Using dataLength in this code will only return the length of the data that has been sent from the NSURLConnection to the delegate in a single call to "connection:didReceiveData:", not the overall length of the data for the entire connection. To achieve this I have added extra properties:

@property (nonatomic, assign)   long long dataWrittenForWholeConnection;
@property (nonatomic, assign)   long long dataLengthOfWholeConnection;

In connection:didReceiveResponse: I used the NSURLResponse method expectedContentLength to obtain the correct estimate of the receiving data's file size for the whole connection.

self.dataWrittenForWholeConnection = 0;
self.dataLengthOfWholeConnection = [httpResponse expectedContentLength];

In connection:didReceiveData: I changed the following:

// 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);
}

By the end of the connection, this should be true:

assert(dataWrittenForWholeConnection == dataLengthOfWholeConnection);

Here is the printout from the same SimpleURLConnections code with my modifications to show what is really happening:

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.

Also, the NSOutputStream method "write:maxLength:" returns "the number of bytes actually written", so for some reason it may choose not to write all the data at once within a single call of "connection:didReceiveData:", thus the use of the do/while loop to check for this. But in this example it writes all the data in a single do/while iteration.

Also, you can use an NSFileHandle instead, and this will always write the whole data sent with each connection:didReceiveData: call, also it's incremental. Note however that writeData: is synchronous.

- (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]);
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!