如何显示文件解压缩进度?

时间:2010-12-27 21:24:14

标签: iphone cocoa unzip

我正在试图找出一种方法来显示当前进度以及将zip文件的内容解压缩并写入磁盘的剩余时间。我目前正在使用此处http://code.google.com/p/ziparchive/找到的ZipArchiver类,它运行良好。问题是,很多都是用C ++编写的,我没有太多的经验。这是相关的功能:

-(BOOL) UnzipFileTo:(NSString*) path overWrite:(BOOL) overwrite
{
    BOOL success = YES;
    int ret = unzGoToFirstFile( _unzFile );
    unsigned char           buffer[4096] = {0};
    NSFileManager* fman = [NSFileManager defaultManager];
    if( ret!=UNZ_OK )
    {
            [self OutputErrorMessage:@"Failed"];
    }

    do{
            if( [_password length]==0 )
                    ret = unzOpenCurrentFile( _unzFile );
            else
                    ret = unzOpenCurrentFilePassword( _unzFile, [_password cStringUsingEncoding:NSASCIIStringEncoding] );
            if( ret!=UNZ_OK )
            {
                    [self OutputErrorMessage:@"Error occurs"];
                    success = NO;
                    break;
            }
            // reading data and write to file
            int read ;
            unz_file_info   fileInfo ={0};
            ret = unzGetCurrentFileInfo(_unzFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
            if( ret!=UNZ_OK )
            {
                    [self OutputErrorMessage:@"Error occurs while getting file info"];
                    success = NO;
                    unzCloseCurrentFile( _unzFile );
                    break;
            }
            char* filename = (char*) malloc( fileInfo.size_filename +1 );
            unzGetCurrentFileInfo(_unzFile, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0);
            filename[fileInfo.size_filename] = '\0';

            // check if it contains directory
            NSString * strPath = [NSString  stringWithCString:filename];
            BOOL isDirectory = NO;
            if( filename[fileInfo.size_filename-1]=='/' || filename[fileInfo.size_filename-1]=='\\')
                    isDirectory = YES;
            free( filename );
            if( [strPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/\\"]].location!=NSNotFound )
            {// contains a path
                    strPath = [strPath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"];
            }
            NSString* fullPath = [path stringByAppendingPathComponent:strPath];

            if( isDirectory )
                    [fman createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:nil error:nil];
            else
                    [fman createDirectoryAtPath:[fullPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
            if( [fman fileExistsAtPath:fullPath] && !isDirectory && !overwrite )
            {
                    if( ![self OverWrite:fullPath] )
                    {
                            unzCloseCurrentFile( _unzFile );
                            ret = unzGoToNextFile( _unzFile );
                            continue;
                    }
            }
            FILE* fp = fopen( (const char*)[fullPath UTF8String], "wb");
            while( fp )
            {
                    read=unzReadCurrentFile(_unzFile, buffer, 4096);
                    if( read > 0 )
                    {
                            fwrite(buffer, read, 1, fp );
                    }
                    else if( read<0 )
                    {
                            [self OutputErrorMessage:@"Failed to reading zip file"];
                            break;
                    }
                    else 
                            break;                          
            }
            if( fp )
            {
                    fclose( fp );
                    // set the orignal datetime property
                    NSDate* orgDate = nil;

                    //{{ thanks to brad.eaton for the solution
                    NSDateComponents *dc = [[NSDateComponents alloc] init];

                    dc.second = fileInfo.tmu_date.tm_sec;
                    dc.minute = fileInfo.tmu_date.tm_min;
                    dc.hour = fileInfo.tmu_date.tm_hour;
                    dc.day = fileInfo.tmu_date.tm_mday;
                    dc.month = fileInfo.tmu_date.tm_mon+1;
                    dc.year = fileInfo.tmu_date.tm_year;

                    NSCalendar *gregorian = [[NSCalendar alloc] 
                                                                     initWithCalendarIdentifier:NSGregorianCalendar];

                    orgDate = [gregorian dateFromComponents:dc] ;
                    [dc release];
                    [gregorian release];
                    //}}


                    NSDictionary* attr = [NSDictionary dictionaryWithObject:orgDate forKey:NSFileModificationDate]; //[[NSFileManager defaultManager] fileAttributesAtPath:fullPath traverseLink:YES];
                    if( attr )
                    {
                            //              [attr  setValue:orgDate forKey:NSFileCreationDate];
                            if( ![[NSFileManager defaultManager] setAttributes:attr ofItemAtPath:fullPath error:nil] )
                            {
                                    // cann't set attributes 
                                    NSLog(@"Failed to set attributes");
                            }

                    }



            }
            unzCloseCurrentFile( _unzFile );
            ret = unzGoToNextFile( _unzFile );
    }while( ret==UNZ_OK && UNZ_OK!=UNZ_END_OF_LIST_OF_FILE );
    return success;
}

我很难弄清楚如何能够插入一些代码,让我显示当前的百分比进度以及解压缩并将所有文件写入磁盘的剩余时间。关于如何实现这一目标的任何想法?

THX

3 个答案:

答案 0 :(得分:3)

不要“插入一些代码来显示进度”。相反,在单独的操作中执行实际工作,并将其进度传递给主线程以呈现给用户。

只需阅读您的代码,就会有一些非常明显的地方可以传递这些信息。例如,有一个内部循环从归档中的单个文件读取数据,并且有一个外部循环,它遍历归档中的文件。您可以轻松创建一组委托消息,这些消息可用于报告正在提取的文件,沿着它的距离以及整个存档中提取的距离。

然后,您可以创建一个特定的委托,知道如何与您的UI(在主线程上)进行交互,并将此进展呈现给用户。

答案 1 :(得分:1)

使用:

https://github.com/mattconnolly/ZipArchive

或来自cocoapods:

pod&#39; ZipArchive&#39;,&#39; 1.1.0&#39;

只需创建一个进度块,将其分配给zip变量,然后让nslog显示。

容易......

使用:

ZipArchive *zip = [[ZipArchive alloc] init];

ZipArchiveProgressUpdateBlock progressBlock = ^ (int percentage, int filesProcessed, int numFiles) {
    NSLog(@"total %d, filesProcessed %d of %d", percentage, filesProcessed, numFiles);
};

zip.progressBlock = progressBlock;

//open file
[zip UnzipOpenFile:path];

//unzip file to
[zip UnzipFileTo:contentPath overWrite:YES];

答案 2 :(得分:0)

这是您用来估计剩余时间的公式:

([TimeTaken] / [NumberOfFilesProcessed])* [NumberOfFilesRemaining] = EstTimeRemaining

TimeTaken:

自进程开始以来经过的秒数。您可以使用NSTimeInterval和NSDate函数来获得此结果。

对于百分比,您只能查看已处理文件的百分比,而不能查看当前解压缩的进度。