ObjC / Cocoa类将大小转换为可读的string?
有没有一种简单的方法来做类似的事情..
[NSMagicDataConverter humanStringWithBytes:20000000]
..会返回“19.1MB”?
这是我自己对这个问题的看法:
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]]; }
默认情况下(如果flags
为0
),它将输出SI单位(十进制)。 您可以设置kUnitStringBinaryUnits
来select适合内存的二进制(基本两个)单位,或者kUnitStringOSNativeUnits
根据操作系统版本自动select单位types(前Leopard获得基数2,后Leopard获得10)。 设置kUnitStringLocalizedFormat
根据用户当前的语言环境kUnitStringLocalizedFormat
格式化string。 例如:
unitStringFromBytes(1073741824, 0); // → "1.07 GB" unitStringFromBytes(1073741824, kUnitStringBinaryUnits); // → "1 GB" unitStringFromBytes(1073741824, kUnitStringOSNativeUnits | kUnitStringLocalizedFormat); // → "1.07 GB" (In Mac OS 10.6) unitStringFromBytes(12345678901234567890123456789, kUnitStringOSNativeUnits | kUnitStringLocalizedFormat); // → "12,345.68 YB" (In Mac OS 10.6, in the US) unitStringFromBytes(12345678901234567890123456789, 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; }
从OS X 10.8和iOS 6开始,您可以使用NSByteCountFormatter 。
你的例子看起来像这样:
[NSByteCountFormatter stringFromByteCount:20000000 countStyle:NSByteCountFormatterCountStyleFile];
我会把这个变成一个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"
下面是一个更类似Objective-C的函数(使用NSNumber,NSArray,NSStirng等)进行这种转换。
这是基于Sidnicious的回答,所以非常感谢在那里做的最初的工作。 也基于维基百科的文章。
一般像这样使用它: [HumanReadableDataSizeHelper humanReadableSizeFromBytes:[NSNumber numberWithDouble:doubleValue]]
。
但是,它看起来像你想国际单位乘数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
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]); }
您可以使用FormatterKit及其TTTUnitOfInformationFormatter
类:
https://github.com/mattt/FormatterKit
它也可以通过CocoaPods获得:
pod 'FormatterKit', '~> 1.1.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]]; }
我知道的问题是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])" }