Get file size in Swift

IosSwift

Ios Problem Overview


I tried several method to get file size, but always get zero.

let path = NSBundle.mainBundle().pathForResource("movie", ofType: "mov")
let attr = NSFileManager.defaultManager().attributesOfFileSystemForPath(path!, error: nil)
if let attr = attr {
    let size: AnyObject? = attr[NSFileSize]
    println("File size = \(size)")
}

I get in log: File size = nil

Ios Solutions


Solution 1 - Ios

Use attributesOfItemAtPath instead of attributesOfFileSystemForPath

  • call .fileSize() on your attr.

    var filePath: NSString = "your path here" var fileSize : UInt64 var attr:NSDictionary? = NSFileManager.defaultManager().attributesOfItemAtPath(filePath, error: nil) if let _attr = attr { fileSize = _attr.fileSize(); }

In Swift 2.0, we use do try catch pattern, like this:

let filePath = "your path here"
var fileSize : UInt64 = 0
  
do {
    let attr : NSDictionary? = try NSFileManager.defaultManager().attributesOfItemAtPath(filePath)
        
    if let _attr = attr {
        fileSize = _attr.fileSize();
    }
} catch {
    print("Error: \(error)")
}

In Swift 3.x/4.0:

let filePath = "your path here"
var fileSize : UInt64

do {
    //return [FileAttributeKey : Any]
    let attr = try FileManager.default.attributesOfItem(atPath: filePath)
    fileSize = attr[FileAttributeKey.size] as! UInt64

    //if you convert to NSDictionary, you can get file size old way as well.
    let dict = attr as NSDictionary
    fileSize = dict.fileSize()
} catch {
    print("Error: \(error)")
}

Solution 2 - Ios

Swift4: URL extension to easily access file attributes

Extension:

extension URL {
    var attributes: [FileAttributeKey : Any]? {
        do {
            return try FileManager.default.attributesOfItem(atPath: path)
        } catch let error as NSError {
            print("FileAttribute error: \(error)")
        }
        return nil
    }

    var fileSize: UInt64 {
        return attributes?[.size] as? UInt64 ?? UInt64(0)
    }

    var fileSizeString: String {
        return ByteCountFormatter.string(fromByteCount: Int64(fileSize), countStyle: .file)
    }

    var creationDate: Date? {
        return attributes?[.creationDate] as? Date
    }
}

Usage:

let fileUrl: URL
print("file size = \(fileUrl.fileSize), \(fileUrl.fileSizeString)")

Solution 3 - Ios

In Swift 3+ you can get the file size directly from the URL, (NS)FileManager is not needed. And ByteCountFormatter is a smart way to display the file size.

let url = Bundle.main.url(forResource:"movie", withExtension: "mov")!
do {
    let resourceValues = try url.resourceValues(forKeys: [.fileSizeKey])
    let fileSize = resourceValues.fileSize!
    print("File size = " + ByteCountFormatter().string(fromByteCount: Int64(fileSize)))
} catch { print(error) }

Actually you can get the file size from the URL even in Swift 2 but the syntax is a bit more cumbersome.

Solution 4 - Ios

SWIFT 3 come from @Hoa's answer and plus a function let UInt64 to readable String.

func sizeForLocalFilePath(filePath:String) -> UInt64 {
	do {
		let fileAttributes = try FileManager.default.attributesOfItem(atPath: filePath)
		if let fileSize = fileAttributes[FileAttributeKey.size]  {
			return (fileSize as! NSNumber).uint64Value
		} else {
			print("Failed to get a size attribute from path: \(filePath)")
		}
	} catch {
		print("Failed to get file attributes for local path: \(filePath) with error: \(error)")
	}
	return 0
}
func covertToFileString(with size: UInt64) -> String {
	var convertedValue: Double = Double(size)
	var multiplyFactor = 0
	let tokens = ["bytes", "KB", "MB", "GB", "TB", "PB",  "EB",  "ZB", "YB"]
	while convertedValue > 1024 {
		convertedValue /= 1024
		multiplyFactor += 1
	}
	return String(format: "%4.2f %@", convertedValue, tokens[multiplyFactor])
}

Solution 5 - Ios

URL extension in Swift to get the file size, if any.

public extension URL {

	var fileSize: Int? {
		let value = try? resourceValues(forKeys: [.fileSizeKey])
		return value?.fileSize
	}
}

The reason for returning an optional Int is because an unknown file size cannot be considered as having a zero size.

Solution 6 - Ios

Here is the answer from Biodave, with the correct file manager call

func sizeForLocalFilePath(filePath:String) -> UInt64 {
    do {
        let fileAttributes = try NSFileManager.defaultManager().attributesOfItemAtPath(filePath)
        if let fileSize = fileAttributes[NSFileSize]  {
            return (fileSize as! NSNumber).unsignedLongLongValue
        } else {
            print("Failed to get a size attribute from path: \(filePath)")
        }
    } catch {
        print("Failed to get file attributes for local path: \(filePath) with error: \(error)")
    }
    return 0
}

For Swift 4.2:

func sizeForLocalFilePath(filePath:String) -> UInt64 {
    do {
        let fileAttributes = try FileManager.default.attributesOfItem(atPath: filePath)
        if let fileSize = fileAttributes[FileAttributeKey.size]  {
            return (fileSize as! NSNumber).uint64Value
        } else {
            print("Failed to get a size attribute from path: \(filePath)")
        }
    } catch {
        print("Failed to get file attributes for local path: \(filePath) with error: \(error)")
    }
    return 0
}

Solution 7 - Ios

Swift 4 solution: This function return MB size.

func sizePerMB(url: URL?) -> Double {
    guard let filePath = url?.path else {
        return 0.0
    }
    do {
        let attribute = try FileManager.default.attributesOfItem(atPath: filePath)
        if let size = attribute[FileAttributeKey.size] as? NSNumber {
            return size.doubleValue / 1000000.0
        }
    } catch {
        print("Error: \(error)")
    }
    return 0.0
}

Solution 8 - Ios

Here is another two different implementation with Swift 4, one is formatted in details and other one is formatted by decimal.

The one with NumberFomatter:

func fileSize(fromPath path: String) -> String? {
    var size: Any?
    do {
        size = try FileManager.default.attributesOfItem(atPath: path)[FileAttributeKey.size]
    } catch (let error) {
        print("File size error: \(error)")
        return nil
    }
    guard let fileSize = size as? UInt64 else {
        return nil
    }
    
    let formatter = NumberFormatter()
    formatter.numberStyle = .decimal
    formatter.formatterBehavior = .behavior10_4
    return formatter.string(from: NSNumber(value: fileSize))
}

And the other one is defining with size units:

func fileSize(fromPath path: String) -> String? {
    guard let size = try? FileManager.default.attributesOfItem(atPath: path)[FileAttributeKey.size],
        let fileSize = size as? UInt64 else {
        return nil
    }
   
    // bytes
    if fileSize < 1023 {
        return String(format: "%lu bytes", CUnsignedLong(fileSize))
    }
    // KB
    var floatSize = Float(fileSize / 1024)
    if floatSize < 1023 {
        return String(format: "%.1f KB", floatSize)
    }
    // MB
    floatSize = floatSize / 1024
    if floatSize < 1023 {
        return String(format: "%.1f MB", floatSize)
    }
    // GB
    floatSize = floatSize / 1024
    return String(format: "%.1f GB", floatSize)
}

Solution 9 - Ios

Try This.

let MyUrl = NSURL(fileURLWithPath: "*** Custom File Path ***")                  
let fileAttributes = try! NSFileManager.defaultManager().attributesOfItemAtPath(MyUrl.path!)
let fileSizeNumber = fileAttributes[NSFileSize] as! NSNumber
let fileSize = fileSizeNumber.longLongValue
var sizeMB = Double(fileSize / 1024)
sizeMB = Double(sizeMB / 1024)
print(String(format: "%.2f", sizeMB) + " MB")

Solution 10 - Ios

In Swift 3.0 try the following:

let fileSize = try! FileManager.default.attributesOfItem(atPath: "/bin/bash")[FileAttributeKey.size] as! Int

or even better:

let fileSize = (try! FileManager.default.attributesOfItem(atPath: "/bin/bash")[FileAttributeKey.size] as! NSNumber).uint64Value

Solution 11 - Ios

Inspiration from a few other answers.

extension URL {
	var filesize: Int? {
		let set = Set.init([URLResourceKey.fileSizeKey])
		var filesize: Int?		
		do {
			let values = try self.resourceValues(forKeys: set)
			if let theFileSize = values.fileSize {
				filesize = theFileSize
			}
		}
		catch {
			print("Error: \(error)")
		}
		return filesize
	}
	
	var filesizeNicelyformatted: String? {
		guard let fileSize = self.filesize else {
			return nil
		}
		return ByteCountFormatter.init().string(fromByteCount: Int64(fileSize))
	}
}

Solution 12 - Ios

Here's a compact version written as happy method in Swift 2.0 for iOS9 via Xcode7:

func sizeForLocalFilePath(filePath:String) -> UInt64 {
    do {
        let fileAttributes = try NSFileManager().attributesOfFileSystemForPath(filePath)
        if let fileSize = fileAttributes[NSFileSystemSize] as? UInt64 {
            return fileSize
        } else {
            print("Failed to get a size attribute from path: \(filePath)")
        }
    } catch {
        print("Failed to get file attributes for local path: \(filePath) with error: \(error)")
    }
    return 0
}

Enjoy!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGralexView Question on Stackoverflow
Solution 1 - IosDuyen-HoaView Answer on Stackoverflow
Solution 2 - IosgheclipseView Answer on Stackoverflow
Solution 3 - IosvadianView Answer on Stackoverflow
Solution 4 - IosJeromeView Answer on Stackoverflow
Solution 5 - IosbohernaView Answer on Stackoverflow
Solution 6 - IosGuy BrookerView Answer on Stackoverflow
Solution 7 - IosAhmed LotfyView Answer on Stackoverflow
Solution 8 - IosabdullahselekView Answer on Stackoverflow
Solution 9 - IosProgramer_saeedView Answer on Stackoverflow
Solution 10 - IosAlexVView Answer on Stackoverflow
Solution 11 - IosJonnyView Answer on Stackoverflow
Solution 12 - IosBiodaveView Answer on Stackoverflow