【问题标题】:Creating a ZIP archive from a Cocoa application从 Cocoa 应用程序创建 ZIP 存档
【发布时间】:2010-12-28 01:00:34
【问题描述】:

是否存在与 Java 包 java.util.zip 中包含的类等效的 Objective-C 类?
执行 CLI 命令是唯一的选择吗?

【问题讨论】:

    标签: objective-c cocoa zip archive


    【解决方案1】:

    【讨论】:

    • ZipKit 似乎比 ZipArchive 更好地命名它的方法(即使我不明白为什么它会在它的添加方法前加上前缀)。
    • 如果 Apple 在 Cocoa 中添加同名的方法,则为类别方法添加前缀或后缀有助于避免名称冲突。
    • ZipKit 现在位于 github.com/kolpanic/ZipKit 并且不再在 bitbucket 上(令人震惊)
    【解决方案2】:

    查看http://code.google.com/p/ziparchive/。这是一个用于压缩文件的类。 Google 是您的朋友!

    【讨论】:

      【解决方案3】:

      除了在您自己的进程中读取和写入 zip 存档之外,使用 NSTask 运行 zipunzip 也没什么丢人的。

      【讨论】:

      • 使用此方法将允许不更改代码以支持新功能。我想知道当您选择一个文件/目录,然后从菜单中选择“压缩”时,Finder 到底做了什么。 Finder 使用哪个可执行文件?
      【解决方案4】:
      【解决方案5】:

      查看zipzap,我的快速 zip 文件 I/O 库。

      【讨论】:

        【解决方案6】:

        从 iOS8/OSX10.10 开始,有一种内置方法可以使用 NSFileCoordinatorReadingOptions.ForUploading 创建 zip 存档。一个没有任何非 Cocoa 依赖项的创建 zip 档案的简单示例:

        public extension NSURL {
        
            /// Creates a zip archive of the file/folder represented by this URL and returns a references to the zipped file
            ///
            /// - parameter dest: the destination URL; if nil, the destination will be this URL with ".zip" appended
            func zip(dest: NSURL? = nil) throws -> NSURL {
                let destURL = dest ?? self.URLByAppendingPathExtension("zip")
        
                let fm = NSFileManager.defaultManager()
                var isDir: ObjCBool = false
        
                let srcDir: NSURL
                let srcDirIsTemporary: Bool
                if let path = self.path where self.fileURL && fm.fileExistsAtPath(path, isDirectory: &isDir) && isDir.boolValue == true {
                    // this URL is a directory: just zip it in-place
                    srcDir = self
                    srcDirIsTemporary = false
                } else {
                    // otherwise we need to copy the simple file to a temporary directory in order for
                    // NSFileCoordinatorReadingOptions.ForUploading to actually zip it up
                    srcDir = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent(NSUUID().UUIDString)
                    try fm.createDirectoryAtURL(srcDir, withIntermediateDirectories: true, attributes: nil)
                    let tmpURL = srcDir.URLByAppendingPathComponent(self.lastPathComponent ?? "file")
                    try fm.copyItemAtURL(self, toURL: tmpURL)
                    srcDirIsTemporary = true
                }
        
                let coord = NSFileCoordinator()
                var error: NSError?
        
                // coordinateReadingItemAtURL is invoked synchronously, but the passed in zippedURL is only valid 
                // for the duration of the block, so it needs to be copied out
                coord.coordinateReadingItemAtURL(srcDir, options: NSFileCoordinatorReadingOptions.ForUploading, error: &error) { (zippedURL: NSURL) -> Void in
                    do {
                        try fm.copyItemAtURL(zippedURL, toURL: destURL)
                    } catch let err {
                        error = err as NSError
                    }
                }
        
                if srcDirIsTemporary { try fm.removeItemAtURL(srcDir) }
                if let error = error { throw error }
                return destURL
            }
        }
        
        public extension NSData {
            /// Creates a zip archive of this data via a temporary file and returns the zipped contents
            func zip() throws -> NSData {
                let tmpURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent(NSUUID().UUIDString)
                try self.writeToURL(tmpURL, options: NSDataWritingOptions.DataWritingAtomic)
                let zipURL = try tmpURL.zip()
                let fm = NSFileManager.defaultManager()
                let zippedData = try NSData(contentsOfURL: zipURL, options: NSDataReadingOptions())
                try fm.removeItemAtURL(tmpURL) // clean up
                try fm.removeItemAtURL(zipURL)
                return zippedData
            }
        }
        

        【讨论】:

        • 这很好,但反过来呢?也就是说,有一个 zip 文件,然后像读取目录一样读取其内容?
        • 我看了但找不到任何类似的方法可以反过来。我对这个答案投了赞成票,因为它太棒了。但是,在我的 Mac 应用程序中,我改为使用 NSTask 来调用 /usr/bin/zip 和 /usr/bin/unzip。这很简单,提供了很多 documented 选项来控制行为,在我的例子中,它使用的代码比这更少。
        • 为什么这种方法没有更普及?一个内置的解决方案,不需要您需要维护的任何额外库,完美。将其“翻译”为目标 c,它似乎也可以工作。
        【解决方案7】:

        answer of @marcprux 翻译成Objective-C。如果这对您有用,请相信他的回答:

        NSURL+Compression.h

        #import <Foundation/Foundation.h>
        
        
        @interface NSURL (NSURLExtension)
        
        - (NSURL*)zip;
        
        @end
        

        NSURL+Compression.m

        #import "NSURL+Compression.h"
        
        
        @implementation NSURL (NSURLExtension)
        
        
        -(NSURL*)zip
        {
          BOOL   isDirectory;
          BOOL   hasTempDirectory = FALSE;
          NSURL* sourceURL;
        
          NSFileManager* fileManager = [NSFileManager defaultManager];
          BOOL           fileExists  = [fileManager fileExistsAtPath:self.path isDirectory:&isDirectory];
        
          NSURL* destinationURL = [self URLByAppendingPathExtension:@"zip"];
        
          if(fileExists && isDirectory)
          {
            sourceURL = self;
          }
        
          else
          {
            sourceURL = [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
            [fileManager createDirectoryAtURL:sourceURL withIntermediateDirectories:TRUE attributes:nil error:nil];
        
            NSString* pathComponent = self.lastPathComponent ? self.lastPathComponent : @"file";
            [fileManager copyItemAtURL:self toURL:[sourceURL URLByAppendingPathComponent:pathComponent] error:nil];
        
            hasTempDirectory = TRUE;
          }
        
          NSFileCoordinator* fileCoordinator = [[NSFileCoordinator alloc] init];
        
          [fileCoordinator coordinateReadingItemAtURL:sourceURL options:NSFileCoordinatorReadingForUploading error:nil byAccessor:^(NSURL* zippedURL)
           {
            [fileManager copyItemAtURL:zippedURL toURL:destinationURL error:nil];
           }];
        
          if(hasTempDirectory)
          {
            [fileManager removeItemAtURL:sourceURL error:nil];
          }
        
          return destinationURL;
        }
        
        
        @end
        

        NSData+Compression.h

        #import <Foundation/Foundation.h>
        
        
        @interface NSData (NSDataExtension)
        
        - (NSData*)zip;
        
        @end
        

        NSData+Compression.m

        #import "NSData+Compression.h"
        #import "NSURL+Compression.h"
        
        
        @implementation NSData (NSDataExtension)
        
        
        // Creates a zip archive of this data via a temporary file and returns the zipped contents
        // Swift to objective c from https://stackoverflow.com/a/32723162/
        -(NSData*)zip
        {
          NSURL* temporaryURL = [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
          [self writeToURL:temporaryURL options:NSDataWritingAtomic error:nil];
          NSURL* zipURL = [temporaryURL zip];
        
          NSFileManager* fileManager = [NSFileManager defaultManager];
          NSData*        zippedData  = [NSData dataWithContentsOfURL:zipURL options:NSDataReadingMapped error:nil];
        
          [fileManager removeItemAtURL:temporaryURL error:nil];
          [fileManager removeItemAtURL:zipURL error:nil];
          
          return zippedData;
        }
        
        
        @end
        

        如果有任何改进,请告诉我。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-04-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-02-06
          • 2022-06-24
          • 2010-11-12
          相关资源
          最近更新 更多