2009-02-21 21 views

Trả lời

18

Đây là mất của riêng tôi về vấn đề này:

enum { 
    kUnitStringBinaryUnits  = 1 << 0, 
    kUnitStringOSNativeUnits = 1 << 1, 
    kUnitStringLocalizedFormat = 1 << 2 
}; 

NSString* unitStringFromBytes(double bytes, uint8_t flags){ 

    static const char units[] = { '\0', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' }; 
    static int maxUnits = sizeof units - 1; 

    int multiplier = (flags & kUnitStringOSNativeUnits && !leopardOrGreater() || flags & kUnitStringBinaryUnits) ? 1024 : 1000; 
    int exponent = 0; 

    while (bytes >= multiplier && exponent < maxUnits) { 
     bytes /= multiplier; 
     exponent++; 
    } 
    NSNumberFormatter* formatter = [[[NSNumberFormatter alloc] init] autorelease]; 
    [formatter setMaximumFractionDigits:2]; 
    if (flags & kUnitStringLocalizedFormat) { 
     [formatter setNumberStyle: NSNumberFormatterDecimalStyle]; 
    } 
    // Beware of reusing this format string. -[NSString stringWithFormat] ignores \0, *printf does not. 
    return [NSString stringWithFormat:@"%@ %cB", [formatter stringFromNumber: [NSNumber numberWithDouble: bytes]], units[exponent]]; 
} 

Theo mặc định (nếu 0 được truyền cho flags), nó sẽ ra SI đơn vị (cơ sở mười). Bạn có thể đặt kUnitStringBinaryUnits để chọn các đơn vị nhị phân (cơ số hai) phù hợp với bộ nhớ, hoặc kUnitStringOSNativeUnits để có loại đơn vị được chọn tự động dựa trên phiên bản hệ điều hành (trước báo được cơ sở hai, sau báo được mười cơ sở). Đặt kUnitStringLocalizedFormat định dạng chuỗi dựa trên ngôn ngữ hiện tại của người dùng. Ví dụ:

unitStringFromBytes(1073741824, 0); // → "1.07 GB" 
unitStringFromBytes(1073741824, kUnitStringBinaryUnits); // → "1 GB" 
unitStringFromBytes(1073741824, kUnitStringOSNativeUnits | kUnitStringLocalizedFormat); // → "1.07 GB" (In Mac OS 10.6) 
unitStringFromBytes(123456789, kUnitStringOSNativeUnits | kUnitStringLocalizedFormat); // → "12,345.68 YB" (In Mac OS 10.6, in the US) 
unitStringFromBytes(123456789, kUnitStringOSNativeUnits | kUnitStringLocalizedFormat); // → "12.345,68 YB" (In Mac OS 10.6, in Spain) 

Dưới đây là các chức năng helper cần thiết cho các đơn vị hệ điều hành bản địa:

BOOL leopardOrGreater(){ 
    static BOOL alreadyComputedOS = NO; 
    static BOOL leopardOrGreater = NO; 
    if (!alreadyComputedOS) { 
     SInt32 majorVersion, minorVersion; 
     Gestalt(gestaltSystemVersionMajor, &majorVersion); 
     Gestalt(gestaltSystemVersionMinor, &minorVersion); 
     leopardOrGreater = ((majorVersion == 10 && minorVersion >= 5) || majorVersion > 10); 
     alreadyComputedOS = YES; 
    } 
    return leopardOrGreater; 
} 
5
NSString *stringFromFileSize(NSInteger theSize) 
{ 
    /* 
    From http://snippets.dzone.com/posts/show/3038 with slight modification 
    */ 
    float floatSize = theSize; 
    if (theSize<1023) 
     return([NSString stringWithFormat:@"%i bytes",theSize]); 
    floatSize = floatSize/1024; 
    if (floatSize<1023) 
     return([NSString stringWithFormat:@"%1.1f KB",floatSize]); 
    floatSize = floatSize/1024; 
    if (floatSize<1023) 
     return([NSString stringWithFormat:@"%1.1f MB",floatSize]); 
    floatSize = floatSize/1024; 

    return([NSString stringWithFormat:@"%1.1f GB",floatSize]); 
} 
+5

Tôi khuyên bạn nên tạo tham số 'theSize' là loại 'size_t', là số nguyên 64 bit. Phương pháp trên sẽ thất bại sau 2 gigabyte. – NilObject

+1

Xin lưu ý rằng việc sử dụng 1024 làm cơ sở so với 1000 không nhất quán với Nguyên tắc giao diện người và do đó, bất kỳ ứng dụng nào sử dụng mã này đều có thể bị từ chối khỏi App Store. –

+1

Chuỗi có định dạng không tôn trọng các bản địa hóa (ví dụ: ký hiệu dấu tách thập phân) - điều này phải được thực hiện bằng trình định dạng số như đã thấy ở trên – monkeydom

22

tôi sẽ mush này thành một lớp con NSFormatter.

#import <Foundation/Foundation.h> 

@interface SOFileSizeFormatter : NSNumberFormatter 
{ 
    @private 
    BOOL useBaseTenUnits; 
} 

/** Flag signaling whether to calculate file size in binary units (1024) or base ten units (1000). Default is binary units. */ 
@property (nonatomic, readwrite, assign, getter=isUsingBaseTenUnits) BOOL useBaseTenUnits; 

@end 

static const char sUnits[] = { '\0', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' }; 
static int sMaxUnits = sizeof sUnits - 1; 

@implementation SOFileSizeFormatter 

@synthesize useBaseTenUnits; 

- (NSString *) stringFromNumber:(NSNumber *)number 
{ 
    int multiplier = useBaseTenUnits ? 1000 : 1024; 
    int exponent = 0; 

    double bytes = [number doubleValue]; 

    while ((bytes >= multiplier) && (exponent < sMaxUnits)) { 
     bytes /= multiplier; 
     exponent++; 
    } 

    return [NSString stringWithFormat:@"%@ %cB", [super stringFromNumber: [NSNumber numberWithDouble: bytes]], sUnits[exponent]]; 
} 

@end 

Cách sử dụng:

NSString *path = ...; // path to a file of 1,500,000 bytes 
NSString *sizeString = nil; 

NSNumber *sizeAttrib = [[[NSFileManager defaultManager] attributesOfItemAtPath:path error:NULL]objectForKey:NSFileSize]; 

SOFileSizeFormatter *sizeFormatter = [[[SOFileSizeFormatter alloc] init] autorelease]; 
[sizeFormatter setMaximumFractionDigits:2]; 

sizeString = [sizeFormatter stringFromNumber:sizeAttrib]; 
// sizeString ==> @"1.43 MB" 

[sizeFormatter setUseBaseTenUnits:YES]; 
sizeString = [sizeFormatter stringFromNumber:sizeAttrib]; 
// sizeString ==> @"1.5 MB" 
+0

Tôi đã làm điều này nhưng chỉ có hai phương thức: stringFromSize: && stringFromSpeed: – Arvin

6

Đây là một chức năng C-như Objective hơn (sử dụng NSNumber, NSArray, NSStirng, vv ...) để thực hiện chuyển đổi này.

Điều này dựa trên câu trả lời của Sidnicious, do đó, cảm ơn bạn đã thực hiện công việc ban đầu ở đó. Cũng dựa trên các bài viết trên Wikipedia.

Sử dụng thông thường như sau: [HumanReadableDataSizeHelper humanReadableSizeFromBytes:[NSNumber numberWithDouble:doubleValue]].

Nhưng, có vẻ như bạn muốn đơn vị với một số nhân 1024 SI, do đó bạn sẽ sử dụng nó như thế này: [HumanReadableDataSizeHelper humanReadableSizeFromBytes:[NSNumber numberWithDouble:doubleValue] useSiPrefixes:YES useSiMultiplier:NO]

Lý do tôi mặc định tiền tố nhị phân (ki, Mi) là vì những dường như là nhất tiền tố đơn vị thích hợp được đặt để sử dụng cho các kích thước dữ liệu trên máy tính. Những gì bạn yêu cầu là đơn vị SI tiền tố nhưng sử dụng một số nhân 1024, về mặt kỹ thuật không chính xác. Mặc dù tôi sẽ lưu ý rằng tiền tố SI cho bội số của 1024 là khá phổ biến và tiền tố nhị phân không được chấp nhận tốt (theo Wikipedia).

HumanReadableDataSizeHelper.h

@interface HumanReadableDataSizeHelper : NSObject 


/** 
    @brief Produces a string containing the largest appropriate units and the new fractional value. 
    @param sizeInBytes The value to convert in bytes. 

    This function converts the bytes value to a value in the greatest units that produces a value >= 1 and returns the new value and units as a string. 

    The magnitude multiplier used is 1024 and the prefixes used are the binary prefixes (ki, Mi, ...). 
*/ 
+ (NSString *)humanReadableSizeFromBytes:(NSNumber *)sizeInBytes; 

/** 
    @brief Produces a string containing the largest appropriate units and the new fractional value. 
    @param sizeInBytes The value to convert in bytes. 
    @param useSiPrefixes Controls what prefix-set is used. 
    @param useSiMultiplier Controls what magnitude multiplier is used. 

    This function converts the bytes value to a value in the greatest units that produces a value >= 1 and returns the new value and units as a string. 

    When useSiPrefixes is true, the prefixes used are the SI unit prefixes (k, M, ...). 
    When useSiPrefixes is false, the prefixes used are the binary prefixes (ki, Mi, ...). 

    When useSiMultiplier is true, the magnitude multiplier used is 1000 
    When useSiMultiplier is false, the magnitude multiplier used is 1024. 
*/ 
+ (NSString *)humanReadableSizeFromBytes:(NSNumber *)sizeInBytes useSiPrefixes:(BOOL)useSiPrefixes useSiMultiplier:(BOOL)useSiMultiplier; 


@end 

HumanReadableDataSizeHelper.m

@implementation HumanReadableDataSizeHelper 


+ (NSString *)humanReadableSizeFromBytes:(NSNumber *)sizeInBytes 
{ 
    return [self humanReadableSizeFromBytes:sizeInBytes useSiPrefixes:NO useSiMultiplier:NO]; 
} 


+ (NSString *)humanReadableSizeFromBytes:(NSNumber *)sizeInBytes useSiPrefixes:(BOOL)useSiPrefixes useSiMultiplier:(BOOL)useSiMultiplier 
{ 
    NSString *unitSymbol = @"B"; 
    NSInteger multiplier; 
    NSArray *prefixes; 

    if (useSiPrefixes) 
    { 
     /* SI prefixes 
     http://en.wikipedia.org/wiki/Kilo- 
     kilobyte (kB) 10^3  
     megabyte (MB) 10^6  
     gigabyte (GB) 10^9  
     terabyte (TB) 10^12 
     petabyte (PB) 10^15 
     exabyte (EB) 10^18 
     zettabyte (ZB) 10^21 
     yottabyte (YB) 10^24 
     */ 

     prefixes = [NSArray arrayWithObjects: @"", @"k", @"M", @"G", @"T", @"P", @"E", @"Z", @"Y", nil]; 
    } 
    else 
    { 
     /* Binary prefixes 
     http://en.wikipedia.org/wiki/Binary_prefix 
     kibibyte (KiB) 2^10 = 1.024 * 10^3 
     mebibyte (MiB) 2^20 ≈ 1.049 * 10^6 
     gibibyte (GiB) 2^30 ≈ 1.074 * 10^9 
     tebibyte (TiB) 2^40 ≈ 1.100 * 10^12 
     pebibyte (PiB) 2^50 ≈ 1.126 * 10^15 
     exbibyte (EiB) 2^60 ≈ 1.153 * 10^18 
     zebibyte (ZiB) 2^70 ≈ 1.181 * 10^21 
     yobibyte (YiB) 2^80 ≈ 1.209 * 10^24 
     */ 

     prefixes = [NSArray arrayWithObjects: @"", @"ki", @"Mi", @"Gi", @"Ti", @"Pi", @"Ei", @"Zi", @"Yi", nil]; 
    } 

    if (useSiMultiplier) 
    { 
     multiplier = 1000; 
    } 
    else 
    { 
     multiplier = 1024; 
    } 

    NSInteger exponent = 0; 
    double size = [sizeInBytes doubleValue]; 

    while ((size >= multiplier) && (exponent < [prefixes count])) 
    { 
     size /= multiplier; 
     exponent++; 
    } 

    NSNumberFormatter* formatter = [[[NSNumberFormatter alloc] init] autorelease]; 
    [formatter setMaximumFractionDigits:2]; 
    [formatter setNumberStyle:NSNumberFormatterDecimalStyle]; // Uses localized number formats. 

    NSString *sizeInUnits = [formatter stringFromNumber:[NSNumber numberWithDouble:size]]; 

    return [NSString stringWithFormat:@"%@ %@%@", sizeInUnits, [prefixes objectAtIndex:exponent], unitSymbol]; 
} 


@end 
98

Bắt đầu từ OS X 10.8 và iOS 6, bạn có thể sử dụng NSByteCountFormatter.

dụ của bạn sẽ trông như thế này:

[NSByteCountFormatter stringFromByteCount:20000000 countStyle:NSByteCountFormatterCountStyleFile]; 
+4

Điều này thực sự cần được đánh dấu là câu trả lời được chấp nhận ngay bây giờ. :) –

+2

Nhược điểm duy nhất để sử dụng điều này là định dạng được buộc bằng cách sử dụng ngôn ngữ hiện tại. – Dids

1
- (id)transformedValue:(id)value 
{ 

    double convertedValue = [value doubleValue]; 
    int multiplyFactor = 0; 

    NSArray *tokens = @[@"bytes",@"KB",@"MB",@"GB",@"TB"]; 

    while (convertedValue > 1024) { 
     convertedValue /= 1024; 
     multiplyFactor++; 
    } 

    return [NSString stringWithFormat:@"%4.2f %@",convertedValue, tokens[multiplyFactor]]; 
} 
+0

Mã của bạn là tốt nhưng trên OSX bạn phải xem xét nhiều trong số 1000 thay vì 1024 kể từ nhà sản xuất đĩa cứng, cũng như cho Finder, 1 GB = 1000 MB :-) – Mike97

0

Tôi biết những câu hỏi được cho Obj C nhưng nếu có ai tìm kiếm một phiên bản nhanh chóng:

public static func fileSizeDisplay(fromBytes:Int) -> String { 
     let display = ["bytes","KB","MB","GB","TB","PB"] 
     var value:Double = Double(fromBytes) 
     var type = 0 
     while (value > 1024){ 
      value /= 1024 
      type = type + 1 

     } 
     return "\(String(format:"%g", value)) \(display[type])" 

    } 
Các vấn đề liên quan