【问题标题】:finding out the downloaded image file size in IOS在IOS中找出下载的图像文件大小
【发布时间】:2012-12-02 00:13:47
【问题描述】:

您好,我想运行一个线程并检查当前下载的文件大小。

这是我用的

UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://lasp.colorado.edu/home/wp-content/uploads/2011/03/suncombo1.jpg"]]];

NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];

NSString *jpegFilePath = [NSString stringWithFormat:@"%@/test.jpeg",docDir];
NSData *data2 = [NSData dataWithData:UIImageJPEGRepresentation(image, 1.0f)];//1.0f = 100% quality
[data2 writeToFile:jpegFilePath atomically:YES];
downloadStatus.text =[NSString stringWithFormat:@"size: %zd", malloc_size(data2)];

[image release];

我也尝试将 malloc_size(data2) 更改为图像,但这又不是真正的结果。我知道这没有线程并且在下载过程中不检查但是我应该在这里使用什么来查看文件大小?

【问题讨论】:

  • 简单来说就是使用NSDatalength实例方法。您将获得不同的文件大小,因为经过UIImageUIImageJPEGRepresentation 转换的文件不同。实际上,您的可疑结果是正确的。请参阅我的更新答案。

标签: iphone ios xcode download file-handling


【解决方案1】:

几个观察:

  1. 您的问题假定您尝试检索 NSData 的大小失败。他们不是。获取NSData 大小的正确方法是通过length

  2. 不过,您的困惑源于一个错误的假设,即在通过UIImageUIImageJPEGRepresentation 的往返过程中获取外部生成的JPEG 将产生相同的NSData。这本来是极不可能的。有太多不同的 JPG 设置可以更改(请参阅JPEG Wikipedia page)。我们当然不知道原始文件使用了哪些设置。我知道UIImage 和/或UIImageJPEGRepresentation 改变了文件的色彩空间。我敢打赌它还会做很多其他事情。

  3. 所以你的结果是正确的。原始文件为 2.6mb,生成的文件为 4.5mb。如果将compressionQuality 从 1.0 更改为 0.99,则生成的文件只有 1.4mb!但是如果你想要原始文件,只需先保存它(就像我在下面做的那样)。

考虑以下代码,它下载图像文件,保存它,将其加载到UIImage,通过UIImageJPEGRepresentation 重新提取它,并保存图像的另一个副本:

// let's make filenames where we'll store the files

NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *suncomboOrig = [documentsPath stringByAppendingPathExtension:@"suncombo1-orig.jpg"];
NSString *suncomboReprocessed = [documentsPath stringByAppendingPathExtension:@"suncombo1-reprocessed.jpg"];

// let's download the original suncombo1.jpg and save it in Documents and display the size

NSURL *url = [NSURL URLWithString:@"http://lasp.colorado.edu/home/wp-content/uploads/2011/03/suncombo1.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
NSLog(@"original = %d", [data length]);
[data writeToFile:suncomboOrig atomically:NO];

// let's load that into a UIImage

UIImage *image = [UIImage imageWithData:data];

// let's extract data out of the image and write that to Documents, too, also logging the size of that

NSData *data2 = UIImageJPEGRepresentation(image, 1.0);
NSLog(@"reprocessed = %d", [data2 length]);
[data2 writeToFile:suncomboReprocessed atomically:NO];

它的作用是报告:

2012-12-13 22:30:39.576 imageapp [90647:c07] 原始 = 2569128 2012-12-13 22:30:40.141 imageapp [90647:c07] 重新处理 = 4382876

所以我保存的第一个文件(我怀疑它与您服务器上的文件相同)是 2.5mb,在往返UIImage 并通过 4.3mb 重新提取后的文件。如果我查看上面代码保存的两个文件,我可以确认这些NSData 大小是正确的。


我最初的答案是基于这样的假设,即 OP 无法检索 NSData 的大小,或者这个简单问题背后存在一些微妙的问题(例如想要在下载开始之前获取大小) .无论如何,我已经在上面扩展了我的答案,但出于历史目的,我会保留我的原始答案:

原答案:

NSData 属性 length 告诉您下载了多少字节。例如。 [data2 length].

如果它真的很大,您可以使用NSURLConnection 异步下载它,这取决于您的Web 服务器,可能会在方法didReceiveResponse 中提供下载开始之前的总文件大小(使用expectedContentLength 属性在NSHTTPURLResponse *response 参数)。

NSURLConnection 下载的另一个好处是,您不必在下载时将整个文件加载到内存中,而是可以将其直接流式传输到持久存储,如果您'同时下载多个大文件。如果您正在下载大小合理的文件,使用NSURLConnection 下载是多余的,但在下载大文件并且您想要一个进度指示器(或者想要在下载开始之前获取文件大小)时它会很好。

但如果您只想知道有多少字节下载到您的NSData,请使用length

【讨论】:

  • 我就是这样做的。但它仍然没有给出准确的结果。我选择了一张大小为 1.5 MB 的图片,它向我展示了 5xxxxxx 个字节。然而,前一个是 2.5 MB,结果是 4xxxxxx 字节。所以我根本没有得到任何可靠的结果!
  • @SarpKaya 您从错误的假设开始,即通过将外部生成的 JPEG 放入 NSData,然后将其加载到 UIImage,然后通过 UIImageJPEGRepresentation 提取会给您同一个文件。如果 JPEG 来自外部来源,则不太可能。所以[data2 length] 是正确的。如果您想要原始文件,请在第一次检索后立即保存并绕过UIImageUIImageJPEGRepresentation。请参阅我更新的答案中的代码。
【解决方案2】:

您可以只使用 C FILE 类来获取文件大小。

 FILE * handle = fopen([jpegFilePath UTF8String], "r");
 fseek(handle, EOF); // seek to end of file
 int size = ftell(handle); // returns position in bytes
 fclose();

【讨论】:

  • 第 2 和第 4 行给出错误,第 2 行需要 3,第 4 行需要一个参数。
  • 我已将其更改为 FILE * handle = fopen([jpegFilePath UTF8String], "r"); fseek(句柄,0,SEEK_END); int size = ftell(句柄); fseek(句柄,0,SEEK_SET); fclose(句柄); downloadStatus.text =[NSString stringWithFormat:@"size: %zd", size];现在它就像之前的评论一样有效,但预期的结果仍然不准确......
【解决方案3】:

因为您说“当前”大小并提到了一个线程,所以我猜您正在尝试确定收到的文件大小。在这种情况下,您可以从NSURLConnection 免费获取线程,并且可以在接收到的委托方法中获取数据大小...

为下载的数据创建一个实例变量:

@property (nonatomic, strong) NSMutableData *data;

创建并启动连接:

NSURL *url = [NSURL URLWithString:@"http://lasp.colorado.edu/home/wp-content/uploads/2011/03/suncombo1.jpg"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];

self.data = [NSMutableData data];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

NSURLConnectionDataDelegate 中实现所需的方法。对于您的问题,特殊部分是这样的:

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [self.data appendData:data];

    NSUInteger bytesSoFar = [self.data length];
    // you're on the app main thread here, so you can do something
    // to the UI to indicate progress
    downloadStatus.text = [NSString stringWithFormat@"size: %d", bytesSoFar];
}

rest of the protocol is here 上的一个很好的文档。连接完成后,您可以像使用dataWithContentsOfURL 一样创建映像...

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {

    UIImage *image = [[UIImage alloc] initWithData:self.data];
    downloadStatus.text = [NSString stringWithFormat@"size: %d", [self.data length]];
}

【讨论】:

  • 这并不重要,但顺便说一句,在 iOS 中,didReceiveData(和 didReceiveResponse)已从 NSURLConnectionDelegate 中移出(如果您转到 iOS 版本的 @ 987654334@page,它们被混淆地标记为已弃用),现在位于NSURLConnectionDataDelegate
  • 我真的希望 Apple 能够清理这方面的文档。 (叹气。)我见过不止一个“哦,天哪,它已被弃用!”在 S.O. 上发帖
  • 是的。我很高兴有来自 Google 和 MSFT 的激烈竞争。对于这三者的开发者和客户来说,这应该是一个黄金时代。
  • 第三行的第一个表示:Assigning to 'NSMutableData' from in compatible type 'id'
  • 哦,我错过了声明上的星号。会补充的。 (第一行)
猜你喜欢
  • 2018-02-27
  • 1970-01-01
  • 2016-01-19
  • 2019-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-20
相关资源
最近更新 更多