Skip to content

Instantly share code, notes, and snippets.

@atifaziz
Last active August 29, 2015 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save atifaziz/9109568 to your computer and use it in GitHub Desktop.
Save atifaziz/9109568 to your computer and use it in GitHub Desktop.
Custom formatter in F# & C# for formatting byte (file/disk/stream) sizes/lengths (e.g. 1.1MB, 2.3GB, 4 bytes, etc.)
using System;
// Adapted from: http://stackoverflow.com/questions/128618/c-file-size-format-provider
// Credit: http://flimflan.com/blog/FileSizeFormatProvider.aspx
public sealed class ByteSizeFormatProvider : IFormatProvider, ICustomFormatter
{
public object GetFormat(Type formatType)
{
return formatType == typeof(ICustomFormatter) ? this : null;
}
private const string FormatSpecifier = "SZ";
private const decimal OneKiloByte = 1024m;
private const decimal OneMegaByte = OneKiloByte * 1024m;
private const decimal OneGigaByte = OneMegaByte * 1024m;
public string Format(string format, object arg, IFormatProvider formatProvider)
{
if (format == null || !format.StartsWith(FormatSpecifier, StringComparison.Ordinal))
return DefaultFormat(format, arg, formatProvider);
if (arg is string)
return DefaultFormat(format, arg, formatProvider);
decimal size;
try
{
size = Convert.ToDecimal(arg, formatProvider);
}
catch (InvalidCastException)
{
return DefaultFormat(format, arg, formatProvider);
}
// TODO: Localization of byte(s), KB, MB, etc.
string suffix;
var ignorePrecision = false;
if (size > OneGigaByte)
{
size /= OneGigaByte;
suffix = "GB";
}
else if (size > OneMegaByte)
{
size /= OneMegaByte;
suffix = "MB";
}
else if (size > OneKiloByte)
{
size /= OneKiloByte;
suffix = "KB";
}
else if (size == 1)
{
suffix = " byte";
ignorePrecision = true;
}
else
{
suffix = " bytes";
ignorePrecision = true;
}
var precision = ignorePrecision ? "0" : format.Substring(FormatSpecifier.Length);
return size.ToString(GetPrecisionFormat(precision), formatProvider) + suffix;
}
static string GetPrecisionFormat(string precision)
{
if (string.IsNullOrEmpty(precision))
return GetPrecisionFormat("2");
if (precision.Length == 1)
{
switch (precision[0])
{
case '0': return "N0";
case '1': return "N1";
case '2': return "N2";
case '3': return "N3";
case '4': return "N4";
}
}
return "N" + precision;
}
static string DefaultFormat(string format, object arg, IFormatProvider formatProvider)
{
var formattable = arg as IFormattable;
return formattable != null
? formattable.ToString(format, formatProvider)
: arg.ToString();
}
}
open System
type ByteSizeFormatProvider() =
let formatSpecifier = "SZ"
let kiloByte = 1024m
let megaByte = kiloByte * 1024m
let gigaByte = megaByte * 1024m
let rec getPrecisionFormat precision =
if String.IsNullOrEmpty(precision) then getPrecisionFormat "2"
else match precision with
| "0" -> "N0"
| "1" -> "N1"
| "2" -> "N2"
| "3" -> "N3"
| "4" -> "N4"
| _ -> "N" + precision
let defaultFormat format formatProvider (arg : obj) =
match arg with
| :? IFormattable as formattable -> formattable.ToString(format, formatProvider)
| _ -> arg.ToString()
interface IFormatProvider with
member this.GetFormat(formatType) =
if formatType = typeof<ICustomFormatter> then this :> obj else null
interface ICustomFormatter with
member this.Format(format, arg, formatProvider) =
if (format = null
|| not (format.StartsWith(formatSpecifier, StringComparison.Ordinal))
|| arg :? string) then
arg |> defaultFormat format formatProvider
else
let size = try Some(Convert.ToDecimal(arg, formatProvider))
with | :? InvalidCastException -> None
match size with
| None -> arg |> defaultFormat format formatProvider
| Some(size) ->
let (size, suffix, ignorePrecision) =
if (size > gigaByte) then (size / gigaByte, "GB", false)
else if (size > megaByte) then (size / megaByte, "MB", false)
else if (size > kiloByte) then (size / kiloByte, "KB", false)
else if (size = 1m ) then (size, " byte", true)
else (size, " bytes", true)
let precision = if ignorePrecision then "0" else format.Substring(formatSpecifier.Length)
size.ToString(getPrecisionFormat precision, formatProvider) + suffix
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment