Holen Sie sich die Dateigröße in Swift


73

Ich habe verschiedene Methoden ausprobiert, um die Dateigröße zu ermitteln, aber immer Null.

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

Ich bekomme im Log: File size = nil


Sind Sie sicher, dass sich die Datei im App-Bundle auf der obersten Ebene befindet?
— Zaph

4
Oder versuchen Sie, AttributeOfItemAtPath anstelle von AttributenOfFileSystemForPath zu verwenden. Sie können .fileSize () auf attr aufrufen, um die Dateigröße abzurufen.
— Duyen-Hoa

1
@ tyt_g207 Ich glaube, das ist die richtige Lösung, aber Sie sollten sie wahrscheinlich als Antwort anstelle eines Kommentars ausschreiben, damit zukünftige Antwortsuchende sie leichter finden können.
— Lyndsey Scott

Antworten:


128

Verwenden Sie attributesOfItemAtPathanstelle von attributesOfFileSystemForPath + .fileSize () auf Ihrem 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 verwenden wir das folgende Fangmuster:

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

3
ist es nur ich, der denkt, dass Swift 2 die Dinge nur noch viel schlimmer gemacht hat. Ich war vollkommen zufrieden mit & error. try-catch, die keine Ausdrücke sind, ist scheiße.
— Martin Algesten

1
Sie können jederzeit try?eine optionale Rücksendung verwenden und erhalten.
— HAT

1
Was ist das Ergebnis? meins war zB 32768.0ist das Byte? so ziemlich 32KB?
— David Seek

1
@BrandonA es ist in Byte
— Duyen-Hoa

36

Swift4: URL-Erweiterung für den einfachen Zugriff auf Dateiattribute

Erweiterung:

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

Verwendung:

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

1
URLstellt die Dateiattribute direkt mit bereit resourceValues(forKeys.
— Vadian

Dies ist die beste Antwort. Sollte die akzeptierte Antwort sein
— Ahufford

19

SWIFT 3 stammt aus der Antwort von @ Hoa und plus einer Funktion, die UInt64 zu einem lesbaren String macht.

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

2
Funktioniert gut, bis auf einen Fehler bei covertToFileString. Ersetzen Sie while size > 1024durch while convertedValue > 1024, um eine Endlosschleife zu vermeiden
— Nicolas Lauquin

16

In Swift 3+ können Sie die Dateigröße direkt von der URL abrufen, (NS)FileManagerwird nicht benötigt. Und ByteCountFormatterist eine clevere Möglichkeit, die Dateigröße anzuzeigen.

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

Eigentlich kann man die Dateigröße URLsogar in Swift 2 abrufen, aber die Syntax ist etwas umständlicher.


9

Hier ist die Antwort von Biodave mit dem richtigen Dateimanager-Aufruf

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
}

Für 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
}

8

Swift 4-Lösung: Diese Funktion gibt die MB-Größe zurück.

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
}

Ich bin wirklich gestolpert, bis ich das sage. Hat fast das Gleiche getan, aber die Pfadeigenschaft der URL nicht verwendet. Danke, Kumpel!
— Felipe

Wie kann man dafür sorgen, dass die KB-Größe zurückgegeben wird?
— Khodour.F

7

Hier sind zwei weitere verschiedene Implementierungen mit Swift 4 , eine ist detailliert formatiert und die andere ist dezimal formatiert.

Der mit 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))
}

Und der andere definiert mit Größeneinheiten:

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

6

Versuche dies.

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

6

URL-Erweiterung in Swift, um die Dateigröße zu ermitteln, falls vorhanden.

public extension URL {

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

Der Grund für die Rückgabe eines optionalen Int liegt darin, dass eine unbekannte Dateigröße nicht als Null angesehen werden kann.


1

Versuchen Sie in Swift 3.0 Folgendes:

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

oder noch besser:

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

Wie ist der zweite besser? Warum sollte man die automatische NSNumber-Konvertierung nicht verwenden? Auch sollten Sie versuchen? und wie? mit if- oder guard-Anweisung als Dateioperation kann fehlschlagen.
— Tapani

1

Inspiration von ein paar anderen Antworten.

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

0

Hier ist eine kompakte Version, die in Swift 2.0 für iOS9 über Xcode7 als Happy-Methode geschrieben wurde:

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
}

Genießen!


Das funktioniert nicht. Es überprüft die Dateisystemattribute, nicht das Attribut der Datei selbst.
— Guy Brooker
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.