2009-02-21 74 views
28

有一个简单的办法做这样的事情..ObjC /可可类将大小转换为可读的字符串?

[NSMagicDataConverter humanStringWithBytes:20000000] 

..这将返回“19.1MB”?

+14

NSByteCountFormatter在iOS 6.0以上版本以及OS X 10.8或更高版本 – 2013-06-21 18:18:18

+0

http://stackoverflow.com/a/ 7846956/944634 – 2013-08-03 15:13:48

回答

18

这是我自己取的问题:

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

默认情况下(如果0传递为flags),它会输出SI单位(基地10次)。您可以设置kUnitStringBinaryUnits选择适合内存的二进制(基本两个)单位,或者kUnitStringOSNativeUnits根据操作系统版本自动选择单位类型(预先Leopard获得基数为2,后Leopard获得基数为10)。设置kUnitStringLocalizedFormat根据用户当前的语言环境设置字符串的格式。例如:

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) 

下面是OS本地单元所需的辅助函数:

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

我会建议使'theSize'参数为'size_t'类型,这是一个64位整数。上述方法在2千兆字节之后会失败。 – NilObject 2009-02-21 14:36:11

+1

请注意,使用1024作为基础而不是1000与人机界面指南不一致,因此,使用此代码的任何应用程序都可能会被App Store拒绝。 – 2011-06-11 16:22:55

+1

带格式的字符串不尊重本地化(例如小数点分隔符) - 这应该使用上面所示的数字格式化程序完成 – monkeydom 2011-11-04 11:23:40

22

我会玉米粥到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 

用法:

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

这是一个比较客观的类似C的功能(使用的NSNumber,NSArray中,NSStirng等)做这种转换。

这是基于Sidnicious的回答,所以非常感谢在那里完成的最初工作。也基于维基百科的文章。

一般使用如下:[HumanReadableDataSizeHelper humanReadableSizeFromBytes:[NSNumber numberWithDouble:doubleValue]]

但是,它看起来像你想SI单位有1024乘数,因此会使用这样的:[HumanReadableDataSizeHelper humanReadableSizeFromBytes:[NSNumber numberWithDouble:doubleValue] useSiPrefixes:YES useSiMultiplier:NO]

我默认为二进制前缀(KI,MI)的原因是因为那些似乎是最将适当的单位前缀设置为用于计算机上数据的大小。你所要求的是SI单位的前缀,但使用1024的乘数,在技术上是不正确的。虽然我会注意到,1024的倍数的SI前缀是相当常见的,并且二进制前缀不被很好接受(根据维基百科)。

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

在OS X 10.8和iOS 6开始,你可以使用NSByteCountFormatter

你的榜样应该是这样的:

[NSByteCountFormatter stringFromByteCount:20000000 countStyle:NSByteCountFormatterCountStyleFile]; 
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

我知道这个问题是对的OBJ C,但如果有人寻找一个迅速版本:

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

    } 
相关问题