如何在Swift中以编程方式获取iPad / iPhone应用程序的大小

时间:2014-12-26 20:21:32

标签: ios iphone ipad swift

我正在尝试以编程方式获取应用的大小。该应用程序下载了大量的音频文件,我正在尝试检查当我删除文件时,应用程序大小会按预期减少。到目前为止,我知道如何做到这一点的唯一方法是查看iPad的设置,但那里的数字似乎总是不正确。

func getAppSize(){
    let paths : NSArray = NSSearchPathForDirectoriesInDomains(.LibraryDirectory, .UserDomainMask, true)
    var errorP = NSErrorPointer()
    let pathDictionary: NSDictionary = NSFileManager.defaultManager().attributesOfFileSystemForPath(paths.firstObject as String, error: errorP)!
    if(pathDictionary.count != 0){
        var fileSystemSizeInBytes: Double = pathDictionary.objectForKey("NSFileSystemSize") as Double
        var fileSystemSizeInMegaBytes : Double = fileSystemSizeInBytes/1000000
        println("Total Space: \(fileSystemSizeInMegaBytes) MB")
    }else{

    }
}

目前我只使用File-System Attirbute Key作为文件系统大小,我希望它是我当前应用程序的大小,但由于它返回249 GB,它显然可以读取我的整个MacBook文件系统大小,而不是模拟器的文档路径。

我查看了其他属性键选项,发现:

let NSFileSystemSize: NSString!
let NSFileSystemFreeSize: NSString!
let NSFileSystemNodes: NSString!
let NSFileSystemFreeNodes: NSString!
let NSFileSystemNumber: NSString!

但是,我还没有找到一个指定应用程序占用的实际空间大小的键。我想也许有办法获得所有节点,然后加上它们的大小,但我不太清楚如何做到这一点。

修改 因此捆绑包似乎给了我我的应用程序大小,但没有我保存到文档路径中的任何mp3文件。我猜我可能会把它们保存到错误的地方或者什么东西,这里是我将它们保存到应用程序的简化版本。

//Make HTTP Request Ect... before here...
if(data.length > 1000){
    let documentPath = NSSearchPathForDirectoriesInDomains(.LibraryDirectory, .UserDomainMask, true)
    let uuid = NSUUID().UUIDString
    let localUrl = uuid + ".mp3"
    let destPath = (documentPath[0] as String) + "/" + localUrl
    data.writeToFile(destPath, atomically: true)
    var error: NSErrorPointer = nil
    data.writeToFile(destPath, options: NSDataWritingOptions.DataWritingAtomic, error: error)
    if(error != nil){
        println("data write error: \(error.memory?.localizedDescription)")
    }
}

5 个答案:

答案 0 :(得分:3)

According to the docs," OS X和iOS中的文件系统处理数据文件,应用程序和与操作系统本身相关的文件的持久存储。"另外according to the docs," NSBundle对象表示文件系统中的一个位置,该位置对可以在程序中使用的代码和资源进行分组,"所以你的应用程序的主要包是其文件所在的位置。根据{{​​3}},每个iOS应用程序都包含一个包,文档目录,库和tmp。

要获取应用的总大小,请通过包,文档,库和tmp子路径进行枚举,例如:

func appSize() {

    // Go through the app's bundle
    let bundlePath = NSBundle.mainBundle().bundlePath
    let bundleArray:NSArray = NSFileManager.defaultManager().subpathsOfDirectoryAtPath(bundlePath, error: nil)!
    let bundleEnumerator = bundleArray.objectEnumerator()
    var fileSize: UInt64 = 0

    while let fileName:String = bundleEnumerator.nextObject() as? String {
        let fileDictionary:NSDictionary = NSFileManager.defaultManager().attributesOfItemAtPath(bundlePath.stringByAppendingPathComponent(fileName), error: nil)!
        fileSize += fileDictionary.fileSize();
    }

    // Go through the app's document directory
    let documentDirectory:NSArray = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, .UserDomainMask, true)
    let documentDirectoryPath:NSString = documentDirectory[0] as NSString
    let documentDirectoryArray:NSArray = NSFileManager.defaultManager().subpathsOfDirectoryAtPath(documentDirectoryPath, error: nil)!
    let documentDirectoryEnumerator = documentDirectoryArray.objectEnumerator()

    while let file:String = documentDirectoryEnumerator.nextObject() as? String {
        let attributes:NSDictionary = NSFileManager.defaultManager().attributesOfItemAtPath(documentDirectoryPath.stringByAppendingPathComponent(file), error: nil)!
        fileSize += attributes.fileSize();
    }

    // Go through the app's library directory
    let libraryDirectory:NSArray = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.LibraryDirectory, NSSearchPathDomainMask.UserDomainMask, true)
    let libraryDirectoryPath:NSString = libraryDirectory[0] as NSString
    let libraryDirectoryArray:NSArray = NSFileManager.defaultManager().subpathsOfDirectoryAtPath(libraryDirectoryPath, error: nil)!
    let libraryDirectoryEnumerator = libraryDirectoryArray.objectEnumerator()

    while let file:String = libraryDirectoryEnumerator.nextObject() as? String {
        let attributes:NSDictionary = NSFileManager.defaultManager().attributesOfItemAtPath(libraryDirectoryPath.stringByAppendingPathComponent(file), error: nil)!
        fileSize += attributes.fileSize();
    }

    // Go through the app's tmp directory
    let tmpDirectoryPath:NSString = NSTemporaryDirectory()
    let tmpDirectoryArray:NSArray = NSFileManager.defaultManager().subpathsOfDirectoryAtPath(tmpDirectoryPath, error: nil)!
    let tmpDirectoryEnumerator = tmpDirectoryArray.objectEnumerator()

    while let file:String = tmpDirectoryEnumerator.nextObject() as? String {
        let attributes:NSDictionary = NSFileManager.defaultManager().attributesOfItemAtPath(tmpDirectoryPath.stringByAppendingPathComponent(file), error: nil)!
        fileSize += attributes.fileSize();
    }

    var fileSystemSizeInMegaBytes : Double = Double(fileSize)/1000000
    println("Total App Space: \(fileSystemSizeInMegaBytes) MB")
}

答案 1 :(得分:2)

您正在计算库文件夹的大小。不是您的应用程序目录文件夹大小。

根据NSSearchPathDirectory

  

<强> NSLibraryDirectory

     

各种用户可见的文档,支持和配置文件   (/库)。

     

适用于iOS 2.0及更高版本。

您应该更改文件保存和计算代码:

<强>存储

//Make HTTP Request Ect... before here...
if(data.length > 1000)
{
    let documentPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
    let uuid = NSUUID().UUIDString
    let localUrl = uuid + ".mp3"
    let destPath = (documentPath[0] as String) + "/" + localUrl
    data.writeToFile(destPath, atomically: true)
    var error: NSErrorPointer = nil
    data.writeToFile(destPath, options: NSDataWritingOptions.DataWritingAtomic, error: error)
    if(error != nil){
        println("data write error: \(error.memory?.localizedDescription)")
    }
}

<强>计算:

func getAppSize()
{
    let paths : NSArray   = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
    let path : NSString   = paths.firstObject? as NSString
    let files : NSArray   = NSFileManager.defaultManager().subpathsOfDirectoryAtPath(path, error: nil)!
    let dirEnumerator     = files.objectEnumerator()
    var totalSize: UInt64 = 0
    let fileManager       = NSFileManager.defaultManager();
    while let file:String = dirEnumerator.nextObject() as? String
    {
        let attributes:NSDictionary = fileManager.attributesOfItemAtPath(path.stringByAppendingPathComponent(file), error: nil)!
        totalSize += attributes.fileSize();
    }

    var fileSystemSizeInMegaBytes : Double = Double(totalSize)/1000000
    println("Total Space: \(fileSystemSizeInMegaBytes) MB")
}

答案 2 :(得分:2)

更新并重构@ lyndsey-scott对 Swift 3 的回答。我修改了代码,以Float64的形式返回大小(以兆字节为单位),而不是将其打印到控制台,因为这适合我的目的。

private class func appSizeInMegaBytes() -> Float64 { // approximate value

    // create list of directories
    var paths = [Bundle.main.bundlePath] // main bundle
    let docDirDomain = FileManager.SearchPathDirectory.documentDirectory
    let docDirs = NSSearchPathForDirectoriesInDomains(docDirDomain, .userDomainMask, true)
    if let docDir = docDirs.first {
        paths.append(docDir) // documents directory
    }
    let libDirDomain = FileManager.SearchPathDirectory.libraryDirectory
    let libDirs = NSSearchPathForDirectoriesInDomains(libDirDomain, .userDomainMask, true)
    if let libDir = libDirs.first {
        paths.append(libDir) // library directory
    }
    paths.append(NSTemporaryDirectory() as String) // temp directory

    // combine sizes
    var totalSize: Float64 = 0
    for path in paths {
        if let size = bytesIn(directory: path) {
            totalSize += size
        }
    }
    return totalSize / 1000000 // megabytes
}

private class func bytesIn(directory: String) -> Float64? {
    let fm = FileManager.default
    guard let subdirectories = try? fm.subpathsOfDirectory(atPath: directory) as NSArray else {
        return nil
    }
    let enumerator = subdirectories.objectEnumerator()
    var size: UInt64 = 0
    while let fileName = enumerator.nextObject() as? String {
        do {
            let fileDictionary = try fm.attributesOfItem(atPath: directory.appending("/" + fileName)) as NSDictionary
            size += fileDictionary.fileSize()
        } catch let err {
            print("err getting attributes of file \(fileName): \(err.localizedDescription)")
        }
    }
    return Float64(size)
}

答案 3 :(得分:1)

基于 Lyndsay 的回答,这里是 Swift 5 的更新版本。它使用 ByteCountFormatter 创建一个人类可读的大小表示。

private var appSize: String {
    let bcf = ByteCountFormatter()
    bcf.allowedUnits = [.useMB, .useGB]
    bcf.countStyle = .file
    return bcf.string(fromByteCount: appSizeInBytes())
}

func appSizeInBytes() -> Int64 {
    // create list of directories
    var paths = [Bundle.main.bundlePath] // main bundle
    let docDirs = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
    if let docDir = docDirs.first {
        paths.append(docDir) // documents directory
    }
    let libDirs = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true)
    if let libDir = libDirs.first {
        paths.append(libDir) // library directory
    }
    paths.append(NSTemporaryDirectory() as String) // temp directory

    // combine sizes
    var totalSize: Int64 = 0
    for path in paths {
        totalSize += byteSize(of: path)
    }
    
    return totalSize
}

func byteSize(of directory: String) -> Int64 {
    var size: Int64 = 0
    let fm = FileManager.default
    if let subdirectories = try? fm.subpathsOfDirectory(atPath: directory) {
        subdirectories.forEach { fileName in
            let fileDictionary = try? fm.attributesOfItem(atPath: directory.appending("/" + fileName)) as NSDictionary
            size += Int64(fileDictionary?.fileSize() ?? 0)
        }
    }
    
    return size
}

享受吧!

答案 4 :(得分:0)

你的应用程序大小是什么意思?
如果你担心从网上下载大量数据,按照最佳做法,你应该在Cache目录下载并做好准备在系统需要时驱逐它。或者您可以将它们保存在Documents目录中,并注意为您下载的文件添加“无备份”属性,否则您的应用可能会被拒绝。