37

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.

yasser h
  • 599
  • 2
  • 9
  • 18

6 Answers6

48

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)")
}
LinusGeffarth
  • 27,197
  • 29
  • 120
  • 174
vadian
  • 274,689
  • 30
  • 353
  • 361
  • 3
    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." – Sneha Nov 27 '17 at 05:49
  • should this technique work for MPMedia Item picked by MPMediaPickerController ? – Awais Fayyaz Feb 08 '19 at 10:39
  • @AwaisFayyaz If you can get the URL for the asset, then yes. – vadian Feb 08 '19 at 10:44
  • @vadian 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? – Awais Fayyaz Feb 08 '19 at 10:53
  • @AwaisFayyaz I'm not familiar with this scheme. To get the size you need a `file://` URL in the file system. – vadian Feb 08 '19 at 10:55
  • @Sneha 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() – Alex Bezk Nov 07 '22 at 18:06
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
}
Ahmed Lotfy
  • 3,806
  • 26
  • 28
14

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
    }
Gurjinder Singh
  • 9,221
  • 1
  • 66
  • 58
12

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)
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
sinner
  • 483
  • 3
  • 14
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
    }
}
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)")
        }
    }
    
}
Haseeb Javed
  • 1,769
  • 17
  • 20