Swift - Get file size from url
Asked Answered
F

6

38

i am using documentPicker to get url path of any document and then uploaded to the database. I am choosing file (pdf, txt ..) , the upload is working but i want to limit the size of the file .

 public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {

        self.file = url //url
        self.path = String(describing: self.file!) // url to string
        self.upload = true //set upload to true
        self.attachBtn.setImage(UIImage(named: "attachFilled"), for: .normal)//set image
        self.attachBtn.tintColor = UIColor.black //set color tint
        sendbtn.tintColor = UIColor.white //


        do
        {
            let fileDictionary = try FileManager.default.attributesOfItem(atPath: self.path!)
            let fileSize = fileDictionary[FileAttributeKey.size]
            print ("\(fileSize)")
        } 
        catch{
            print("Error: \(error)")
        }

    }

I get the error message , this file does not exist , where does the document picker save the file and how to get his attributes.

Foreign answered 5/5, 2017 at 5:39 Comment(3)
Maybe this is the one you are looking for: #19316033Pernicious
Thank you , the link helped me.Foreign
You are welcome ;-)Pernicious
I
49

First of all, in the file system you get the path of a URL with the path property.

self.path = url.path

But you don't need that at all. You can retrieve the file size from the URL directly:

self.path = String(describing: self.file!) // url to string

do {
    let resources = try url.resourceValues(forKeys:[.fileSizeKey])
    let fileSize = resources.fileSize!
    print ("\(fileSize)")
} catch {
    print("Error: \(error)")
}
Ironsmith answered 5/5, 2017 at 7:19 Comment(6)
in iOS 11, I am getting the error Error Domain=NSCocoaErrorDomain Code=257 "The file couldn’t be opened because you don’t have permission to view it."Coacervate
should this technique work for MPMedia Item picked by MPMediaPickerController ?Multilateral
@AwaisFayyaz If you can get the URL for the asset, then yes.Ironsmith
@Ironsmith I got assetURL of selected Item. This looks like ipod-library://item/item.mp3?id=9046838634016568305 When i tried your code, fileSize is nil. Any ideas?Multilateral
@AwaisFayyaz I'm not familiar with this scheme. To get the size you need a file:// URL in the file system.Ironsmith
@Coacervate I know it has been a long time and you most probably fixed that, but for those who faced the same issue as me as well when I tried to access the resource values. To fix it you need to call: url.startAccessingSecurityScopedResource() and then you can get resourceValues from your url. After you end up with that you should also call: url.stopAccessingSecurityScopedResource()Mendiola
B
27

Swift 4:

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
}
Boondocks answered 8/11, 2017 at 18:15 Comment(0)
B
15

Swift 4.1 & 5

func fileSize(forURL url: Any) -> Double {
        var fileURL: URL?
        var fileSize: Double = 0.0
        if (url is URL) || (url is String)
        {
            if (url is URL) {
                fileURL = url as? URL
            }
            else {
                fileURL = URL(fileURLWithPath: url as! String)
            }
            var fileSizeValue = 0.0
            try? fileSizeValue = (fileURL?.resourceValues(forKeys: [URLResourceKey.fileSizeKey]).allValues.first?.value as! Double?)!
            if fileSizeValue > 0.0 {
                fileSize = (Double(fileSizeValue) / (1024 * 1024))
            }
        }
        return fileSize
    }
Bumpy answered 20/6, 2018 at 15:39 Comment(3)
Too many places where this code could fail. And most importantly it won't work on files > 2GbProceeds
@EvgenBodunov Why won't it work when the file size is over 2GB?Medellin
@KimiChiu He probably assumed Int32.max forgetting that we're 64 bit nowMacario
F
14

It's very easy with latest version of swift to calculate size of file using byte counter formatter:

var fileSizeValue: UInt64 = 0
        
do {
    
    let fileAttribute: [FileAttributeKey : Any] = try FileManager.default.attributesOfItem(atPath: url.path)
    
    if let fileNumberSize: NSNumber = fileAttribute[FileAttributeKey.size] as? NSNumber {
        fileSizeValue = UInt64(fileNumberSize)
        
        let byteCountFormatter: ByteCountFormatter = ByteCountFormatter()
        byteCountFormatter.countStyle = ByteCountFormatter.CountStyle.file
        
        byteCountFormatter.allowedUnits = ByteCountFormatter.Units.useBytes
        print(byteCountFormatter.string(fromByteCount: Int64(fileSizeValue)))

        byteCountFormatter.allowedUnits = ByteCountFormatter.Units.useKB
        print(byteCountFormatter.string(fromByteCount: Int64(fileSizeValue)))

        byteCountFormatter.allowedUnits = ByteCountFormatter.Units.useMB
        print(byteCountFormatter.string(fromByteCount: Int64(fileSizeValue)))
    
    }
    
} catch {
    print(error.localizedDescription)
}
Foxtail answered 24/7, 2017 at 9:58 Comment(0)
I
7
extension URL {
    func fileSize() -> Double {
        var fileSize: Double = 0.0
        var fileSizeValue = 0.0
        try? fileSizeValue = (self.resourceValues(forKeys: [URLResourceKey.fileSizeKey]).allValues.first?.value as! Double?)!
        if fileSizeValue > 0.0 {
            fileSize = (Double(fileSizeValue) / (1024 * 1024))
        }
        return fileSize
    }
}
Idellaidelle answered 3/6, 2020 at 4:48 Comment(1)
Please add commentary to explain what exactly this extension does.Vulva
M
1

Working Solution:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    
    if let videoURL = info[UIImagePickerController.InfoKey.mediaURL] as? NSURL{
        print(videoURL)
        
        do {
            let resources = try videoURL.resourceValues(forKeys:[.fileSizeKey])
            let fileSize : Int = resources.values.first as! Int
            print ((fileSize/1024/1024) )
        } catch {
            print("Error: \(error)")
        }
    }
    
}
Mawkin answered 3/2, 2022 at 11:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.