Get File Size in Swift

Get file size in Swift

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)")
}

How to get file name and file size from UIDocumentPickerViewController in iOS 14?

In your UIDocumentPickerDelegate, you have will end up implementing documentPicker(_:didPickDocumentsAt:), which will give you an array of URLs. You can get the name of a file using url.lastPathComponent.

Regarding the file size, once you have the same URL from above, you can query the file size (may solutions listed here: Swift - Get file size from url):

do {
let attribute = try FileManager.default.attributesOfItem(atPath: url.path)
if let size = attribute[FileAttributeKey.size] as? NSNumber {
let sizeInMB = size.doubleValue / 1000000.0
}
} catch {
print("Error: \(error)")
}

How to get image file size in Swift?

Please check the google for 1 kb to bytes it will be 1000.

https://www.google.com/search?q=1+kb+%3D+how+many+bytes&oq=1+kb+%3D+how+many+bytes&aqs=chrome..69i57.8999j0j1&sourceid=chrome&ie=UTF-8


So while getting the proper size I’ve added multiple scenario by adding image in App Bundle and in photos in simulator.
Well the image which I took from my Mac was of 299.0 KB.


Scenario 1: Adding image to Application Bundle

On adding image in your Xcode the size of the image will remain same in project directory. But you get it from its path the size will be reduced to 257.0 KB. Which is the actual size of the image used in the device or simulator.

    guard let aStrUrl = Bundle.main.path(forResource: "1", ofType: "png") else { return }

let aUrl = URL(fileURLWithPath: aStrUrl)
print("Img size = \((Double(aUrl.fileSize) / 1000.00).rounded()) KB")

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

Scenario 2: Adding image to Photos in Simulator

On adding image to photos in simulator or device the size of the image increased from 299.0 KB to 393.0 KB. Which is the actual size of the image stored in the device or simulator’s document directory.

Swift 4 and earlier

var image = info[UIImagePickerControllerOriginalImage] as! UIImage
var imgData: NSData = NSData(data: UIImageJPEGRepresentation((image), 1))
// var imgData: NSData = UIImagePNGRepresentation(image)
// you can also replace UIImageJPEGRepresentation with UIImagePNGRepresentation.
var imageSize: Int = imgData.count
print("size of image in KB: %f ", Double(imageSize) / 1000.0)

Swift 5

let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage

let imgData = NSData(data: image.jpegData(compressionQuality: 1)!)
var imageSize: Int = imgData.count
print("actual size of image in KB: %f ", Double(imageSize) / 1000.0)

By adding .rounded() it will give you 393.0 KB and without using it it will give 393.442 KB. So please check the image size manually once using the above code. As the size of image may vary in different devices and mac. I've check it only on mac mini and simulator iPhone XS.

Swift - Checking file sizes from a server before downloading is causing a lag in the app

The solution was to use a URL request and use the HTTP method "HEAD". Using the "expectedContentLength", you can find out the size of the file size and this causes no lag compared to the previous method mentioned.

func getFileSize(_ url: URL, completion: @escaping (Int64, Error?) -> Void){
let timeoutInterval = 5.0
var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: timeoutInterval)
request.httpMethod = "HEAD"

let group = DispatchGroup()
group.enter()

URLSession.shared.dataTask(with: request) { (data, response, error) in
let contentLength = response?.expectedContentLength ?? NSURLSessionTransferSizeUnknown
completion(contentLength, error)
group.leave()
}.resume()
}

you can convert the size to MB using the code below if required

let countBytes = ByteCountFormatter()
countBytes.allowedUnits = [.useMB]
countBytes.countStyle = .file
let fileSizeInMB = countBytes.string(fromByteCount: Int64(ENTERYOURVALUEHERE))

Get file size of PHAsset without loading in the resource?

You can grab the fileSize of a PHAsset and convert it to human readable form like this:

      let resources = PHAssetResource.assetResources(for: yourAsset) // your PHAsset

var sizeOnDisk: Int64? = 0

if let resource = resources.first {
let unsignedInt64 = resource.value(forKey: "fileSize") as? CLong
sizeOnDisk = Int64(bitPattern: UInt64(unsignedInt64!))
}

Then use your sizeOnDisk variable and pass it into a method like this...

func converByteToHumanReadable(_ bytes:Int64) -> String {
let formatter:ByteCountFormatter = ByteCountFormatter()
formatter.countStyle = .binary

return formatter.string(fromByteCount: Int64(bytes))
}

How to get file size before downloading from url?

The URL data task is asynchronous. Your code is not waiting until it has completed before displaying the dialog.

It's like sending somebody to the garden to count how many apples he sees lying on the ground, so you can put that number onto a piece of paper. You tell that person to go counting and put the result into a box, where currently the number zero is stored. As soon as the person leaves, you are opening the box and writing down the number you see. Yet the person hasn't even arrived in the garden, nor has the person counted any apples yet. When the person returns, he does as you told him, put the number of counted apples in the box. Now you send the person again, this time counting the numbers or pears he can see in the garden. And again, as soon as the person left, you open up the box and write down the number you see there, but that is still the number from counting apples as the person didn't even have a chance to update that number.

The block you feed to getDownloadSize() will run once the result has been fetched, but the code below that call runs immediately after calling getDownloadSize(), it will not wait until the block has executed.

And it wouldn't be a good idea to change that since fetching the result can take anything from a few seconds to several minutes. If the execution of code would block until the result has been fetched, your entire application would block for that time as well (your UI would completely freeze, no user interaction would be possible).



Related Topics



Leave a reply



Submit