Jak wykryć całkowitą dostępną / wolną przestrzeń dyskową na urządzeniu iPhone / iPad?

147

Szukam lepszego sposobu na programowe wykrywanie dostępnego / wolnego miejsca na dysku na urządzeniu iPhone / iPad.
Obecnie używam NSFileManager do wykrywania miejsca na dysku. Poniżej znajduje się fragment kodu, który działa za mnie:

-(unsigned)getFreeDiskspacePrivate {
NSDictionary *atDict = [[NSFileManager defaultManager] attributesOfFileSystemForPath:@"/" error:NULL];
unsigned freeSpace = [[atDict objectForKey:NSFileSystemFreeSize] unsignedIntValue];
NSLog(@"%s - Free Diskspace: %u bytes - %u MiB", __PRETTY_FUNCTION__, freeSpace, (freeSpace/1024)/1024);

return freeSpace;
}


Czy mam rację z powyższym fragmentem? czy jest lepszy sposób na sprawdzenie całkowitej dostępnej / wolnej przestrzeni dyskowej.
Muszę wykryć całkowitą ilość wolnego miejsca na dysku, ponieważ musimy uniemożliwić naszej aplikacji wykonanie synchronizacji w scenariuszu z małą ilością miejsca na dysku.

Code.Warrior
źródło
Mam nadzieję, że link do stackoverflow pomoże ci ...
senthilMuthu
1
Wygląda na to, że kod, którego używa w swoim pytaniu, jest lepszy niż kod w linku, który podałeś (po prostu sprawdza jeden katalog zamiast przechodzić przez wszystkie podkatalogi pod „/”)
Kendall Helmstetter Gelner
Dzięki Michaił za link. Ale szukam całkowitego dostępnego / wolnego miejsca na dysku na urządzeniu iPhone / iPad, a nie tylko konkretnego folderu. Na przykład na iPhonie 32 GB, jeśli całkowity dostępny / wolny rozmiar wynosi 28 GB, powinienem być w stanie wykryć to programowo.
Code.Warrior
Mam nadzieję, że ten link pomoże: jayprakashdubey.blogspot.in/2014/07/…
Jayprakash Dubey

Odpowiedzi:

152

AKTUALIZACJA : Ponieważ od tej odpowiedzi upłynęło dużo czasu i dodano nowe metody / interfejsy API, sprawdź zaktualizowane odpowiedzi poniżej dla Swift itp; Ponieważ sam ich nie używałem, nie mogę za nie ręczyć.

Oryginalna odpowiedź : znalazłem następujące rozwiązanie, które działa dla mnie:

-(uint64_t)getFreeDiskspace {
    uint64_t totalSpace = 0;
    uint64_t totalFreeSpace = 0;
    NSError *error = nil;  
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);  
    NSDictionary *dictionary = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[paths lastObject] error: &error];  

    if (dictionary) {  
        NSNumber *fileSystemSizeInBytes = [dictionary objectForKey: NSFileSystemSize];  
        NSNumber *freeFileSystemSizeInBytes = [dictionary objectForKey:NSFileSystemFreeSize];
        totalSpace = [fileSystemSizeInBytes unsignedLongLongValue];
        totalFreeSpace = [freeFileSystemSizeInBytes unsignedLongLongValue];
        NSLog(@"Memory Capacity of %llu MiB with %llu MiB Free memory available.", ((totalSpace/1024ll)/1024ll), ((totalFreeSpace/1024ll)/1024ll));
    } else {  
        NSLog(@"Error Obtaining System Memory Info: Domain = %@, Code = %ld", [error domain], (long)[error code]);
    }  

    return totalFreeSpace;
}

Zwraca mi dokładnie taki rozmiar, jaki wyświetla iTunes, gdy urządzenie jest podłączone do komputera.

Code.Warrior
źródło
4
Konwersja na zmiennoprzecinkową może dać niedokładne wyniki powyżej około 2 GB. Jeśli chcesz radzić sobie z naprawdę dużymi rozmiarami plików, użyj zamiast tego podwójnego lub długiego podwójnego.
Ash,
Jak zauważył Ash, ta metoda ma niedokładny wynik. W moim iPadzie 2, z 64 GB, zawodzi o +0,25 GB ... Poniższa metoda, opublikowana przez Davida H, daje dokładny wynik przy użyciu vars uint64_t.
Leandro Alves
3
Fragment kodu został zmodyfikowany w celu odzwierciedlenia sugestii od @David H, jak pokazano poniżej.
Code.Warrior
4
+200 MB to nie problem. W Ustawieniach mam „0 bajtów” dostępnej przestrzeni. A kiedy wchodzę i używam mojej aplikacji, ta metoda zgłasza około 150 MB wolnego miejsca. Następnie uzupełniam pozostałą przestrzeń i dopiero wtedy aplikacja się zawiesza. Więc powiedziałbym, że ta metoda daje więcej poprawnych informacji niż to, co widzisz w Ustawieniach.
ancajic
4
Dlaczego nikt nie używa NSUIntegerzamiast takich rzeczy uint64_t? Piszemy Obj-C, a nie C ++ lub C.NSUInteger poda teraz 64-bitową liczbę całkowitą bez znaku, ale jeśli coś się zmieni, wyobrażam sobie, że Apple zaktualizuje to makro (powiedzmy, że 128 bitów w pewnym momencie stanie się rzeczywiste)
Goles
59

Zmienione źródło używające unsigned long long:

- (uint64_t)freeDiskspace
{
    uint64_t totalSpace = 0;
    uint64_t totalFreeSpace = 0;

    __autoreleasing NSError *error = nil;  
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);  
    NSDictionary *dictionary = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[paths lastObject] error: &error];  

    if (dictionary) {  
        NSNumber *fileSystemSizeInBytes = [dictionary objectForKey: NSFileSystemSize];  
        NSNumber *freeFileSystemSizeInBytes = [dictionary objectForKey:NSFileSystemFreeSize];
        totalSpace = [fileSystemSizeInBytes unsignedLongLongValue];
        totalFreeSpace = [freeFileSystemSizeInBytes unsignedLongLongValue];
        NSLog(@"Memory Capacity of %llu MiB with %llu MiB Free memory available.", ((totalSpace/1024ll)/1024ll), ((totalFreeSpace/1024ll)/1024ll));
    } else {  
        NSLog(@"Error Obtaining System Memory Info: Domain = %@, Code = %d", [error domain], [error code]);  
    }  

    return totalFreeSpace;
}

EDYCJA: wygląda na to, że ktoś zmodyfikował ten kod, aby użyć „uint64_t” zamiast „unsigned long long”. Chociaż w dającej się przewidzieć przyszłości powinno to być w porządku, nie są takie same. „uint64_t” ma 64 bity i zawsze nim będzie. Za 10 lat „unsigned long long” może wynosić 128. to mały punkt, ale dlaczego użyłem unsignedLongLong.

David H.
źródło
Nie mam doświadczenia z nowym automatycznym systemem liczenia, ale po co __autoreleasing? Zwykle nie musisz automatycznie publikować zwróconego NSError
wielebnego
To może pomóc: stackoverflow.com/questions/8862023/…
Fabian Kreiser
3
na moim iPodzie Touch 4. generacji z systemem iOS 5.1, NSFileSystemFreeSize nadal zgłasza za dużo o około 200 MB. Wydrukowuję zawartość całego NSDictionary w debugerze ... NSFileSystemSize jest poprawny ... ktoś ma rozwiązanie tego problemu?
Zennichimaro,
@Zennichimaro: Czy rozwiązałeś swój problem? Mam również ten sam problem, otrzymując dodatkowe 0,2 GB, gdy sprawdzam wolne miejsce na iPadzie. iPad pokazuje 24,1 GB dostępnej przestrzeni, ale w kodzie pokazuje 24,3 GB.
Sudheer Kumar Palchuri
1
@Diejmon nie możesz zapytać NSNumber o całkowitą wielkość tego typu. Dlatego do takich rzeczy wolę jednostkę o znanej wielkości bitowej. Chociaż technicznie zgadzam się z twoim stwierdzeniem, mam już wystarczająco dużo ostrzeżeń, aby poradzić sobie z używaniem NSInteger i ciągów formatujących! 64 bity na pewno wystarczą za mojego i twojego życia.
David H
34

Napisałem klasę, aby uzyskać dostępną / używaną pamięć za pomocą Swift. Demo na: https://github.com/thanhcuong1990/swift-disk-status
Swift 4 zaktualizowany.

import UIKit

class DiskStatus {

    //MARK: Formatter MB only
    class func MBFormatter(_ bytes: Int64) -> String {
        let formatter = ByteCountFormatter()
        formatter.allowedUnits = ByteCountFormatter.Units.useMB
        formatter.countStyle = ByteCountFormatter.CountStyle.decimal
        formatter.includesUnit = false
        return formatter.string(fromByteCount: bytes) as String
    }


    //MARK: Get String Value
    class var totalDiskSpace:String {
        get {
            return ByteCountFormatter.string(fromByteCount: totalDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.file)
        }
    }

    class var freeDiskSpace:String {
        get {
            return ByteCountFormatter.string(fromByteCount: freeDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.file)
        }
    }

    class var usedDiskSpace:String {
        get {
            return ByteCountFormatter.string(fromByteCount: usedDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.file)
        }
    }


    //MARK: Get raw value
    class var totalDiskSpaceInBytes:Int64 {
        get {
            do {
                let systemAttributes = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory() as String)
                let space = (systemAttributes[FileAttributeKey.systemSize] as? NSNumber)?.int64Value
                return space!
            } catch {
                return 0
            }
        }
    }

    class var freeDiskSpaceInBytes:Int64 {
        get {
            do {
                let systemAttributes = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory() as String)
                let freeSpace = (systemAttributes[FileAttributeKey.systemFreeSize] as? NSNumber)?.int64Value
                return freeSpace!
            } catch {
                return 0
            }
        }
    }

    class var usedDiskSpaceInBytes:Int64 {
        get {
            let usedSpace = totalDiskSpaceInBytes - freeDiskSpaceInBytes
            return usedSpace
        }
    }

}

Próbny

uzyskaj status miejsca na dysku za pomocą Swift

Cuong Lam
źródło
Czy masz pojęcie, dlaczego MBFormatter jest dostępny? Nie jest nigdzie używany.
Ben Sinclair,
MBFormatter to funkcja konwertująca dowolną wartość na wartość MB. Nie używam go do projektu demonstracyjnego. Ale potrzebuję innego projektu.
Cuong Lam
1
Wspaniale jest umieścić rozszerzenie FileManager.
Leon
2
iTunes pokazuje 18,99 GB za darmo, ale otrzymuję 13,41 GB, gdy używam opisanych metod. Czy ktoś wie, za czym tęsknię?
Vitalii Boiarskyi
1
@CuongLam Błędy podczas rozpakowywania nie są generowane ani przechwytywane przez polecenie do / catch. Przykładowy kod źródłowy powinien być napisany tak, aby poprawnie obsługiwał błędy. stackoverflow.com/questions/34628999/…
SafeFastExpressive
26

Jeśli potrzebujesz sformatowanego ciągu z rozmiarem, możesz rzucić okiem na ładną bibliotekę na GitHub :

#define MB (1024*1024)
#define GB (MB*1024)

@implementation ALDisk

#pragma mark - Formatter

+ (NSString *)memoryFormatter:(long long)diskSpace {
    NSString *formatted;
    double bytes = 1.0 * diskSpace;
    double megabytes = bytes / MB;
    double gigabytes = bytes / GB;
    if (gigabytes >= 1.0)
        formatted = [NSString stringWithFormat:@"%.2f GB", gigabytes];
    else if (megabytes >= 1.0)
        formatted = [NSString stringWithFormat:@"%.2f MB", megabytes];
    else
        formatted = [NSString stringWithFormat:@"%.2f bytes", bytes];

    return formatted;
}

#pragma mark - Methods

+ (NSString *)totalDiskSpace {
    long long space = [[[[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil] objectForKey:NSFileSystemSize] longLongValue];
    return [self memoryFormatter:space];
}

+ (NSString *)freeDiskSpace {
    long long freeSpace = [[[[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil] objectForKey:NSFileSystemFreeSize] longLongValue];
    return [self memoryFormatter:freeSpace];
}

+ (NSString *)usedDiskSpace {
    return [self memoryFormatter:[self usedDiskSpaceInBytes]];
}

+ (CGFloat)totalDiskSpaceInBytes {
    long long space = [[[[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil] objectForKey:NSFileSystemSize] longLongValue];
    return space;
}

+ (CGFloat)freeDiskSpaceInBytes {
    long long freeSpace = [[[[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil] objectForKey:NSFileSystemFreeSize] longLongValue];
    return freeSpace;
}

+ (CGFloat)usedDiskSpaceInBytes {
    long long usedSpace = [self totalDiskSpaceInBytes] - [self freeDiskSpaceInBytes];
    return usedSpace;
}
0x8BADF00D
źródło
2
Aby sformatować, można również użyć NSBytCounterFormatter
Daniel Barden
Nadal jest podatny na ten sam błąd + 200 MB: stackoverflow.com/questions/9270027/…
Paulius Liekis
13

Nie używaj `` bez znaku '', tylko 32 bity przekroczą 4 GB, czyli mniej niż typowe wolne miejsce na iPada / iPhone'a. Użyj unsigned long long (lub uint64_t) i pobierz wartość z NSNumber jako 64-bitową liczbę int za pomocą unsignedLongLongValue.

Christophera Lloyda
źródło
3
To lepsze niż wskazówka - „To prawo” :-) Jak powiedział, oryginalny kod jest po prostu błędny.
David H
13

Jeśli chcesz uzyskać pozostałe wolne miejsce za pomocą Swift, jest to nieco inne. Musisz użyć attributeOfFileSystemForPath () zamiast attributeOfItemAtPath ():

func deviceRemainingFreeSpaceInBytes() -> Int64? {
    let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
    var attributes: [String: AnyObject]
    do {
        attributes = try NSFileManager.defaultManager().attributesOfFileSystemForPath(documentDirectoryPath.last! as String)
        let freeSize = attributes[NSFileSystemFreeSize] as? NSNumber
        if (freeSize != nil) {
            return freeSize?.longLongValue
        } else {
            return nil
        }
    } catch {
        return nil
    }
}

Edycja: Aktualizacja dla Swift 1.0
Edit 2: Aktualizacja dla bezpieczeństwa, korzystając odpowiedź Martina R jest .
Edycja 3: Zaktualizowano dla Swift 2.0 (przez dgellow )

RubenSandwich
źródło
Próbowałem użyć tej odpowiedzi, ale nie można jej skompilować pod GM ([NSObject: AnyObject]? Nie ma członka o nazwie „indeks”). Myślę, że jest to spowodowane podniesioną kwestią tutaj , ale nie rozumiem, jak sprawić, by ta odpowiedź zadziałała w tym kontekście. Każda pomoc mile widziana.
Bryan Hanson
Zaktualizowałem odpowiedź, aby teraz pracować nad Swift 1.0. Ponieważ attributeOfFileSystemForPath zwraca [NSObject: AnyObject]? musisz obsadzić NSDictionary? ponieważ mogłoby to być nil, a następnie rozpakuj słownik, aby go indeksować. (To trochę niebezpieczne, więc zaktualizuję odpowiedź nieco później, wprowadzając bezpieczniejsze rozwiązanie, gdy będę miał czas.)
RubenSandwich,
Dziękuję za aktualizację. Jak się okazuje, na około godzinę przed Twoją odpowiedzią poszedłem naprzód i sformułowałem tę kwestię jako nowe pytanie tutaj . Jest tam teraz odpowiedź, ale ponieważ ta metoda radzenia sobie z opcjami jest dla mnie trochę nieprzejrzysta, chciałbym zobaczyć inne podejście dla Twojej wygody. Pozdrów ode mnie swoją siostrę Rachel.
Bryan Hanson
Bryan, zasugerowałbym pierwszą odpowiedź na twoje pytanie, na które odpowiedziałeś, ponieważ jest to dobre połączenie bezpieczeństwa i przejrzystości. Nie jestem pewien, czy mógłbym udzielić lepszej odpowiedzi niż ta. Opcje opcjonalne mogą na początku być mylące, zdecydowanie sugeruję przeczytanie sekcji podręczników Swift na temat opcji opcjonalnych , jest całkiem dobra.
RubenSandwich
Bardzo doceniane, ponownie zajrzę do tej instrukcji i znalazłem również kilka dobrych pytań SO. Bryan
Bryan Hanson
9

Oto moja odpowiedź i dlaczego jest lepiej.

Odpowiedź (Szybka):

func remainingDiskSpaceOnThisDevice() -> String {
    var remainingSpace = NSLocalizedString("Unknown", comment: "The remaining free disk space on this device is unknown.")
    if let attributes = try? FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory()),
        let freeSpaceSize = attributes[FileAttributeKey.systemFreeSize] as? Int64 {
        remainingSpace = ByteCountFormatter.string(fromByteCount: freeSpaceSize, countStyle: .file)
    }
    return remainingSpace
}

Odpowiedź (Cel-C):

- (NSString *)calculateRemainingDiskSpaceOnThisDevice
{
    NSString *remainingSpace = NSLocalizedString(@"Unknown", @"The remaining free disk space on this device is unknown.");
    NSDictionary *dictionary = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil];
    if (dictionary) {
        long long freeSpaceSize = [[dictionary objectForKey:NSFileSystemFreeSize] longLongValue];
        remainingSpace = [NSByteCountFormatter stringFromByteCount:freeSpaceSize countStyle:NSByteCountFormatterCountStyleFile];
    }
    return remainingSpace;
}

Dlaczego jest lepiej:

  • Wykorzystuje wbudowaną bibliotekę Cocoa NSByteCountFormatter, co oznacza brak szalonych ręcznych obliczeń od bajtów do gigabajtów. Apple robi to za Ciebie!
  • Łatwe do przetłumaczenia: NSByteCountFormatterzrób to za siebie. Np. Jeśli język urządzenia jest ustawiony na angielski, ciąg odczyta 248,8 MB, ale odczyta 248,8 Mo, gdy zostanie ustawiony na francuski, i tak dalej dla innych języków.
  • W przypadku błędu podawana jest wartość domyślna.
ChrisJF
źródło
1
@JuanBoero Opublikowany w Swift 3.1 (wreszcie)!
ChrisJF
7

Ważne wyjaśnienie (przynajmniej dla mnie). Jeśli podłączę iPoda do komputera Mac, są to informacje wyświetlane przez aplikację iTunes.

Informacje o pamięci iPoda z aplikacji iTunes

Kiedy używam powyższego kodu:

long long freeSpace = [[[[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil]
                            objectForKey:NSFileSystemFreeSize] longLongValue];

NSString *free1 = [NSByteCountFormatter stringFromByteCount:freeSpace countStyle:NSByteCountFormatterCountStyleFile];

[label1 setText:free1];

NSString *free2 = [NSByteCountFormatter stringFromByteCount:freeSpace countStyle:NSByteCountFormatterCountStyleBinary];

[label2 setText:free2];

CountStyle NSByteCountFormatterCountStyleFile pokazuje mi: 17,41 GB

CountStyle NSByteCountFormatterCountStyleBinary pokaż mi: 16,22 GB

16,22 GB ( NSByteCountFormatterCountStyleBinary ) Jest to DOKŁADNIE liczba wyświetlana przez aplikację iTunes po podłączeniu iPoda do komputera Mac.

Markus
źródło
może Plik jest tylko dla plików MAC, a nie iOS?
João Nunes
to ta sama ilość bajtów pomnożona jako 1000 (KB, następnie MB, a następnie GB) w porównaniu z 1024.
Jim75,
7

Zaktualizuj za pomocą nowego dokładnego interfejsu API, aby uzyskać dostępny rozmiar na dysku dostępny w systemie iOS11. Oto opis nowego klucza zasobów API:

#if os(OSX) || os(iOS)
/// Total available capacity in bytes for "Important" resources, including space expected to be cleared by purging non-essential and cached resources. "Important" means something that the user or application clearly expects to be present on the local system, but is ultimately replaceable. This would include items that the user has explicitly requested via the UI, and resources that an application requires in order to provide functionality.
/// Examples: A video that the user has explicitly requested to watch but has not yet finished watching or an audio file that the user has requested to download.
/// This value should not be used in determining if there is room for an irreplaceable resource. In the case of irreplaceable resources, always attempt to save the resource regardless of available capacity and handle failure as gracefully as possible.
@available(OSX 10.13, iOS 11.0, *) @available(tvOS, unavailable) @available(watchOS, unavailable)
public var volumeAvailableCapacityFor Usage: Int64? { return _get(.volumeAvailableCapacityForImportantUsageKey) }
#endif

Porównałem wyniki z klucza „ FileAttributeKey.systemFreeSize ” i klucza „ URLResourceKey.volumeAvailableCapacityForImportantUsageKey ” i stwierdziłem, że zwrócone wyniki z formularza „ volumeAvailableCapacityForImportantUsageKey ” dokładnie odpowiadają dostępnej pamięci pokazanej w UI. Porównanie dostępnego wolnego miejsca na dysku Oto szybka realizacja:

class var freeDiskSpaceInBytesImportant:Int64 {
    get {
        do {
            return try URL(fileURLWithPath: NSHomeDirectory() as String).resourceValues(forKeys: [URLResourceKey.volumeAvailableCapacityForImportantUsageKey]).volumeAvailableCapacityForImportantUsage!
        } catch {
            return 0
        }
    }
}
Evilisn Jiang
źródło
Skąd na twoim zrzucie ekranu bierze się „oportunistyczne użycie”?
rshev
Znaleziono go volumeAvailableCapacityForOpportunisticUsageKey.
rshev
Tak rshev, volumeAvailableCapacityForOpportunisticUsageKey otrzymuje na moim zrzucie ekranu „oportunistyczne użycie”
Evilisn Jiang
aby zobaczyć dostępny rozmiar magazynu, powinienem zapytać o NSHomeDirectory()lub NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true). Czy jest jakaś różnica w używaniu tych dwóch?
Suryakant Sharma
7

Można znaleźć inne rozwiązanie z użyciem Swift 4 i extensionktóry daje możliwość dobrego.

Oto UIDevicerozszerzenie.

extension UIDevice {

    func totalDiskSpaceInBytes() -> Int64 {
        do {
            guard let totalDiskSpaceInBytes = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory())[FileAttributeKey.systemSize] as? Int64 else {
                return 0
            }
            return totalDiskSpaceInBytes
        } catch {
            return 0
        }
    }

    func freeDiskSpaceInBytes() -> Int64 {
        do {
            guard let totalDiskSpaceInBytes = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory())[FileAttributeKey.systemFreeSize] as? Int64 else {
                return 0 
            }
            return totalDiskSpaceInBytes
        } catch {
            return 0
        }
    }

    func usedDiskSpaceInBytes() -> Int64 {
        return totalDiskSpaceInBytes() - freeDiskSpaceInBytes()
    }

    func totalDiskSpace() -> String {
        let diskSpaceInBytes = totalDiskSpaceInBytes()
        if diskSpaceInBytes > 0 {
            return ByteCountFormatter.string(fromByteCount: diskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.binary)
        }
        return "The total disk space on this device is unknown"
    }

    func freeDiskSpace() -> String {
        let freeSpaceInBytes = freeDiskSpaceInBytes()
        if freeSpaceInBytes > 0 {
            return ByteCountFormatter.string(fromByteCount: freeSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.binary)
        }
        return "The free disk space on this device is unknown"
    }

    func usedDiskSpace() -> String {
        let usedSpaceInBytes = totalDiskSpaceInBytes() - freeDiskSpaceInBytes()
        if usedSpaceInBytes > 0 {
            return ByteCountFormatter.string(fromByteCount: usedSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.binary)
        }
        return "The used disk space on this device is unknown"
    }

}

I przykładowe użycie:

UIDevice.current.totalDiskSpaceInBytes()
UIDevice.current.totalDiskSpace()
UIDevice.current.freeDiskSpaceInBytes()
UIDevice.current.freeDiskSpace()
UIDevice.current.usedDiskSpaceInBytes()
UIDevice.current.usedDiskSpace()
abdullahselek
źródło
Nie używaj !zamiast tego włóż guarddo sejfu typecastinglub nilsprawdź.
TheTiger
Dzięki za komentarze @TheTiger.
abdullahselek
3

W przypadku iOS> = 6.0 możesz użyć nowego NSByteCountFormatter. Ten kod pobiera liczbę wolnych bajtów pozostałych jako sformatowany ciąg.

NSError *error = nil;
NSArray * const paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSDictionary * const pathAttributes = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[paths firstObject] error:&error];
NSAssert(pathAttributes, @"");
NSNumber * const fileSystemSizeInBytes = [pathAttributes objectForKey: NSFileSystemFreeSize];
const long long numberOfBytesRemaining = [fileSystemSizeInBytes longLongValue];
NSByteCountFormatter *byteCountFormatter = [[NSByteCountFormatter alloc] init];
NSString *formattedNmberOfBytesRemaining = [byteCountFormatter stringFromByteCount:numberOfBytesRemaining];
Robert
źródło
2

Poniższy kod jest implementacją wersji Swift 3.0 odpowiedzi udzielonej wcześniej przez ChrisJF:

func freeSpaceInBytes() -> NSString {

    var remainingSpace = NSLocalizedString("Unknown", comment: "The remaining free disk space on this device is unknown.")

    do {
        let dictionary =  try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory())
        let freeSpaceSize = ((dictionary[FileAttributeKey.systemFreeSize] as AnyObject).longLongValue)!
        remainingSpace = ByteCountFormatter.string(fromByteCount: freeSpaceSize, countStyle: ByteCountFormatter.CountStyle.file)
    }
    catch let error {
        NSLog(error.localizedDescription)
    }

    return remainingSpace as NSString

}
ggruen
źródło
Dlaczego zwraca więcej informacji o miejscu na dysku, niż jest dostępne w iPhonie. Gdy menu ustawień iPhone'ów mówi 998MB, która zwraca 1,2 GB
Nadzieja
1

dla Swift jako rozszerzenie UIDevice

extension UIDevice {
    func freeDiskspace() -> NSString {
        let failedResult: String = "Error Obtaining System Memory"
        guard let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true).last else {
            return failedResult
        }
        do {
            let dictionary = try NSFileManager.defaultManager().attributesOfFileSystemForPath(path)
            if let fileSystemSizeInBytes = dictionary[NSFileSystemSize] as? UInt,
                let freeFileSystemSizeInBytes =     dictionary[NSFileSystemFreeSize] as? UInt {
                    return "Memory \(freeFileSystemSizeInBytes/1024/1024) of \(fileSystemSizeInBytes/1024/1024) Mb available."
            } else {
                    return failedResult
            }
        } catch {
            return failedResult
        }
    }
}

Jak używać:

print("\(UIDevice.currentDevice().freeDiskspace())")

Wynik będzie:

Memory 9656 of 207694 Mb available.
ale_stro
źródło
1

Wiem, że ten post jest trochę stary, ale myślę, że ta odpowiedź może komuś pomóc. Jeśli chcesz poznać wykorzystane / wolne / całkowite miejsce na dysku na urządzeniu, możesz użyć Luminous . Jest napisane w języku Swift. Wystarczy zadzwonić:

Luminous.System.Disk.freeSpace()
Luminous.System.Disk.usedSpace()

lub

Luminous.System.Disk.freeSpaceInBytes()
Luminous.System.Disk.usedSpaceInBytes()
Andrea Mario Lufino
źródło
1

Szybka implementacja powyższego kodu: -

import UIKit

class DiskInformation: NSObject {

    var totalSpaceInBytes: CLongLong = 0; // total disk space
    var totalFreeSpaceInBytes: CLongLong = 0; //total free space in bytes

    func getTotalDiskSpace() -> String { //get total disk space
        do{
        let space: CLongLong = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory())[FileAttributeKey.systemSize] as! CLongLong; //Check for home dirctory and get total system size
            totalSpaceInBytes = space; // set as total space
            return memoryFormatter(space: space); // send the total bytes to formatter method and return the output

        }catch let error{ // Catch error that may be thrown by FileManager
            print("Error is ", error);
        }
        return "Error while getting memory size";
    }

    func getTotalFreeSpace() -> String{ //Get total free space
        do{
            let space: CLongLong = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory())[FileAttributeKey.systemFreeSize] as! CLongLong;
            totalFreeSpaceInBytes = space;
            return memoryFormatter(space: space);

        }catch let error{
            print("Error is ", error);
        }
        return "Error while getting memory size";
    }

    func getTotalUsedSpace() -> String{ //Get total disk usage from above variable
        return memoryFormatter(space: (totalSpaceInBytes - totalFreeSpaceInBytes));
    }

    func memoryFormatter(space : CLongLong) -> String{ //Format the usage to return value with 2 digits after decimal
        var formattedString: String;

        let totalBytes: Double = 1.0 * Double(space);
        let totalMb: Double = totalBytes / (1024 * 1024);
        let totalGb: Double = totalMb / 1024;
        if (totalGb > 1.0){
            formattedString = String(format: "%.2f", totalGb);
        }else if(totalMb >= 1.0){
            formattedString = String(format: "%.2f", totalMb);
        }else{
            formattedString = String(format: "%.2f", totalBytes);
        }
        return formattedString;
    }


}

Zadzwoń z dowolnej innej klasy.

func getDiskInfo(){
        let diskInfo = DiskInformation();
        print("Total disk space is", diskInfo.getTotalDiskSpace(),"Gb");
        print("Total free space is", diskInfo.getTotalFreeSpace(),"Gb");
        print("Total used space is", diskInfo.getTotalUsedSpace(),"Gb");
    }

Podczas testowania zwracanej wartości jest taka sama, jak pokazują inne aplikacje. Przynajmniej w moim iPhonie 6S +. To tylko szybka implementacja powyższej odpowiedzi. A dla mnie zaakceptowana odpowiedź nie zadziałała.

Bikram
źródło
0

Odpowiedź ChrisJF w wersji Swift 2.1 :

func freeSpaceInBytes() -> NSString{

    var remainingSpace = NSLocalizedString("Unknown", comment: "The remaining free disk space on this device is unknown.")

    do {

        let dictionary =  try NSFileManager.defaultManager().attributesOfFileSystemForPath(NSHomeDirectory())
        freeSpaceSize = (dictionary[NSFileSystemFreeSize]?.longLongValue)!
        remainingSpace = NSByteCountFormatter.stringFromByteCount(freeSpaceSize, countStyle: NSByteCountFormatterCountStyle.File)

    }
    catch let error as NSError {

        error.description
        NSLog(error.description)

    }

    return remainingSpace

}
Juan Boero
źródło
0

Rozszerzenie Swift 5 zapewniające FileManagerwłaściwą obsługę błędów i brak automatycznej konwersji ciągów (konwertuj liczbę bajtów na ciąg według własnego uznania). Następuje również FileManagernazewnictwo.

extension FileManager {
    func systemFreeSizeBytes() -> Result<Int64, Error> {
        do {
            let attrs = try attributesOfFileSystem(forPath: NSHomeDirectory())
            guard let freeSize = attrs[.systemFreeSize] as? Int64 else {
                return .failure(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey : "Can't retrieve system free size"]))
            }
            return .success(freeSize)
        } catch {
            return .failure(error)
        }
    }

    func systemSizeBytes() -> Result<Int64, Error> {
         do {
             let attrs = try attributesOfFileSystem(forPath: NSHomeDirectory())
             guard let size = attrs[.systemSize] as? Int64 else {
                 return .failure(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey : "Can't retrieve system size"]))
             }
             return .success(size)
         } catch {
             return .failure(error)
         }
     }
}

Przykładowe użycie:

let freeSizeResult = FileManager.default.systemFreeSizeBytes()
switch freeSizeResult {
case .failure(let error):
    print(error)
case .success(let freeSize):
    let freeSizeString = ByteCountFormatter.string(fromByteCount: freeSize, countStyle: .file)
    print("free size: \(freeSizeString)")
}
ivanzoid
źródło