轻量级 iOS Untar 介绍


原文:http://blog.octo.com/en/category/it-architects-workshop|

 

问题的提出

为什么要untar?

手机 app 中网络连接需要耗费一定的时间。与下载10个1M的小文件相比,一次性下载1个10M的文件显然可以得到性能上的极大提升。

unix 下有一个 tar 命令无人不知。

tar 命令的用途正如维基百科中所说:通常用于将多个文件打包成一个较大的文件,以用于分发和存档的目的。打包之后保留所有的文件系统信息,诸如用户和组权限,日期、以及原来的目录结构。

这正是我们使用tar 的目的。

那么,在 iOS 设备上,如何将一个tar 包 untar(解开)呢?

 

如何解包?

通过 google 搜索,得知 iOS 提供两种解包的方法:

  • BSD libarchive。这个库已经在 iOS 中存在。但却缺少相应的头文件。苹果把这类库叫做“私有 API”。你不能在苹果商店应用中使用私有api。如果只是在越狱的设备中使用,那没有什么问题,但我想将应用发布到AppStore就不行了。
  • Davepeck BSD libarchive。该项目位于 https://github.com/davepeck/iOS-libarchive。这是一个开源项目,davepeck 已经将它迁移到 iOS 上,你可以在你项目中使用它。这个库的实现类似于 Mac 下的 tar 命令。你可以以 gzip 或 bzip 压缩方式创建 tar 包或者解开 tar 包。但是这个库有 617个文件,347606 行代码(没有任何 OC 类的服装),编译后大小为 4.7 M。谨记,如果 app 超过20M的话,就得用 Wifi 来下载了。

为什么不使用 libarchive?

如果使用 libarchive:

  • 我们需要在项目中引入相关代码,这些代码有可能被改变。
  • 代码越多,bug越多。根据麦克康耐尔的《代码大全》,平均每千行代码 15-50 个Bug,因此,在 libarchive 中包含了 5000 个 bug。
  • 如果苹果修改了 API 并中止了对 libarchive 的兼容,你的代码就不再可靠了。

有没有其他办法?我的 app 是肯定要在 AppStore上架的,而且我也不想在我的app 中链接 4.7 M 之巨的难于维护的代码。我决定自己实现一个轻量级的 untar 工具。

怎么做?

Libarchive 编译后有4.7M,但其中许多东西我们并不需要。

我们仅仅需要其中 untar(解包)功能,但下列功能却不需要 :

  • tar 功能 (打包) 。
  • 解压缩(gzip或bzip)。如果想解压缩文件,我们可以先用 zlib 库然后再解包(untar)。没有必要同时解包和解压缩。
  • 对老式 tar 格式的支持(80年代)。
  • 对 unix 所有者及权限支持:哪怕就是你想这样做,iOS也不允许设置权限。
  • 对 simlink、hard links 和 FIFO 等的支持。我们仅仅需要处理的是文件。

解决之道

什么是tar 文件?

tar 文件是由一个个 512 字节的块构成的。

第一个文件的头构成了第一个块,然后是文件内容,然后是新的文件头,新的文件内容。

如下图所示:(H 表示头块,C表示内容块,/ 表示不完全的内容块)

H C C C C C C C C / HC C C C / H H C C C C C C / _ _

在tar 文件最后有两个空块。每个文件总是从整数块开始。有的文件没有内容块(例如文件夹)。每个块都是512字节。

头块中包含许多数据,绝大多数数据对于我们来说是无意义的,我们仅仅需要:

  • 文件名:ASCII编码,以相对路径的形式给出,例如:mydir/myfile.pdf
  • 文件尺寸:   ASCII编码,一个8进制数,单位是字节
  • 文件类型:  我们只需要两种类型:0-文件,5-目录

FileName

          

Size

          

Type

          

通过文件尺寸,我们可以知道下一个文件的头块位于什么位置,以及文件最后一个内容块是哪里。

成果:轻量级的 iOS Untar

够简单的,不是吗?我用 O-C 实现了它,然后放到了 github:https://github.com/mhausherr/Light-Untar-for-iOS

 

代码基于 BSD 协议,你可以在自己的项目里使用它。

是不是比 libarchive 更酷?轻量级的 iOS Untar 仅仅2 个文件,168 行代码,包括注释行和许可声明。

使用方法是包含 .h 文件然后利用 NSFileManager 的createFilesAndDirectoriesAtPath 方法:

1

[[NSFileManager defaultManager] createFilesAndDirectoriesAtPath:@"/path/to/your/extracted/files/" withTarData:tarData error:&error];

tarData 是一个 NSData 对象。你可以用这样来创建它:

1

NSData *tarData = [NSData dataWithContentsOfFile:@"/path/to/your/tar/file.tar"];

性能和安全限制

性能

Libarchive 采用 c 语言编写,当然要比我用 O-C 代码实现要快。

问题是:对于你来说什么更重要?

  • 每次 untar 时快上 40ms?
  • 为你的 app 节省 4.7 M 的存储空间?
  • To save 4.7Mb of the size of your app?

如果是后者,轻量级的 iOS Untar更适合你。

安全

对于 tar 包来说主要的安全问题是什么?

  • 符号链接:有人会在目录中放如符号链接,以此访问外部文件夹。
  • 把 ownership 设为 root 并加上执行权限:有人会以Root权限添加一个可执行文件并执行它。

这些问题在我的代码中都不存在,你可以安全地使用它。

你要知道,它是一个 iOS 库。在 iOS  中,程序在沙盒中运行,系统自身会保证代码的安全性,我们完全不需要做任何事情。

结论

手机应用主要是在低性能设备是运行的。app 编译尺寸非常重要。

如果你需要解决一个简单的问题,首先考虑什么方式最好:一个庞大的框架当然可以为你解决问题。但你真需要这个框架的全部功能吗?还是仅仅需要其中某个功能?

 


你可能感兴趣的:(轻量级 iOS Untar 介绍)