用于将大小转换为人类可读字符串的ObjC/Cocoa类?

dbr*_*dbr 28 cocoa objective-c

有没有一种简单的方法来做...

[NSMagicDataConverter humanStringWithBytes:20000000]
Run Code Online (Sandbox Code Playgroud)

..谁将返回"19.1MB"?

jrc*_*jrc 104

从OS X 10.8和iOS 6开始,您可以使用NSByteCountFormatter.

您的示例如下所示:

[NSByteCountFormatter stringFromByteCount:20000000 countStyle:NSByteCountFormatterCountStyleFile];
Run Code Online (Sandbox Code Playgroud)

  • 这真的应该被标记为现在接受的答案.:) (4认同)
  • 使用它的唯一缺点是使用当前语言环境强制格式化. (2认同)

Bil*_*son 21

我会把它变成一个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
Run Code Online (Sandbox Code Playgroud)

用法:

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"
Run Code Online (Sandbox Code Playgroud)


s4y*_*s4y 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]];
}
Run Code Online (Sandbox Code Playgroud)

默认情况下(如果0传递flags),它将输出SI单位(十进制).您可以设置kUnitStringBinaryUnits选择适合内存的二进制(基数为2)单位,或者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(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)
Run Code Online (Sandbox Code Playgroud)

这是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;
}
Run Code Online (Sandbox Code Playgroud)


dbr*_*dbr 6

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]);
}
Run Code Online (Sandbox Code Playgroud)

  • 我建议将'theSize'参数设为'size_t'类型,这是一个64位整数.上述方法在2千兆字节后会失败. (5认同)

Nat*_*ate 6

这是一个更像Objective 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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)