How to display file unzip progress?

2019-07-16 13:22发布

I am trying to figure out a way to display the current progress as well as the time remaining to unzip and write the contents of a zip file to disk. I am currently using the ZipArchiver class found here http://code.google.com/p/ziparchive/ which is working quite well. Problem is, that a lot of it is written in C++ which i dont have too much experience in. Here is the relevant function:

-(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;
}

I am having a hard time trying to figure out how i would be able to insert some code that would let me display the current percentage progress as well as the time remaining to unzip and write all files to disk. Any ideas on how i could go about achieving this?

thx

3条回答
乱世女痞
2楼-- · 2019-07-16 13:34

This is the equation you use to estimate the time remaining:

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

TimeTaken:

The number of seconds elapsed since the start of the process. You can use NSTimeInterval and the NSDate functions to get this result.

As for percentage, you can only view the percentage of files processed, but not the progress of a current unzip.

查看更多
干净又极端
3楼-- · 2019-07-16 13:37

Use:

https://github.com/mattconnolly/ZipArchive

or from cocoapods:

pod 'ZipArchive', '1.1.0'

Just create a block of progress assign it to your zip variable and let the nslog show you.

Easy ...

Use:

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];
查看更多
你好瞎i
4楼-- · 2019-07-16 13:57

Don't "insert some code to display the progress." Instead, do the actual work in a separate operation, and have that communicate its progress to the main thread for presentation to the user.

Just reading through your code there are a few extremely obvious places to pass this information out. For example, there's an inner loop that reads data from a single file in the archive, and there's an outer loop that iterates over the files in the archive. You could easily create a set of delegate messages that can be used to report which file is being extracted, how far along it is, and how far along in the entire archive the extraction is.

Then you can create a specific delegate that knows how to interact with your UI (on the main thread) and present this progress to the user.

查看更多
登录 后发表回答