Теперь я понимаю, что вы на самом деле просили что-то, что могло бы работать с String.Format () - я думаю, мне следовало прочитать этот вопрос дважды перед публикацией; -)
Мне не нравится решение, в котором вы должны каждый раз явно передавать провайдера формата - из того, что я могу почерпнуть из этой статьи , лучший способ подойти к этому - реализовать FileSize тип, реализующий интерфейс IFormattable.
Я реализовал структуру, которая поддерживает этот интерфейс и может быть преобразована из целого числа. В моих собственных API, связанных с файлами, мои свойства .FileSize возвращают экземпляр FileSize.
Вот код:
using System.Globalization;
public struct FileSize : IFormattable
{
private ulong _value;
private const int DEFAULT_PRECISION = 2;
private static IList<string> Units;
static FileSize()
{
Units = new List<string>(){
"B", "KB", "MB", "GB", "TB"
};
}
public FileSize(ulong value)
{
_value = value;
}
public static explicit operator FileSize(ulong value)
{
return new FileSize(value);
}
override public string ToString()
{
return ToString(null, null);
}
public string ToString(string format)
{
return ToString(format, null);
}
public string ToString(string format, IFormatProvider formatProvider)
{
int precision;
if (String.IsNullOrEmpty(format))
return ToString(DEFAULT_PRECISION);
else if (int.TryParse(format, out precision))
return ToString(precision);
else
return _value.ToString(format, formatProvider);
}
/// <summary>
/// Formats the FileSize using the given number of decimals.
/// </summary>
public string ToString(int precision)
{
double pow = Math.Floor((_value > 0 ? Math.Log(_value) : 0) / Math.Log(1024));
pow = Math.Min(pow, Units.Count - 1);
double value = (double)_value / Math.Pow(1024, pow);
return value.ToString(pow == 0 ? "F0" : "F" + precision.ToString()) + " " + Units[(int)pow];
}
}
И простой модульный тест, который демонстрирует, как это работает:
[Test]
public void CanUseFileSizeFormatProvider()
{
Assert.AreEqual(String.Format("{0}", (FileSize)128), "128 B");
Assert.AreEqual(String.Format("{0}", (FileSize)1024), "1.00 KB");
Assert.AreEqual(String.Format("{0:0}", (FileSize)10240), "10 KB");
Assert.AreEqual(String.Format("{0:1}", (FileSize)102400), "100.0 KB");
Assert.AreEqual(String.Format("{0}", (FileSize)1048576), "1.00 MB");
Assert.AreEqual(String.Format("{0:D}", (FileSize)123456), "123456");
// You can also manually invoke ToString(), optionally with the precision specified as an integer:
Assert.AreEqual(((FileSize)111111).ToString(2), "108.51 KB");
}
Как вы можете видеть, тип FileSize теперь можно правильно отформатировать, а также можно указать количество десятичных знаков, а также применить обычное числовое форматирование, если требуется.
Полагаю, вы могли бы пойти еще дальше, например, разрешив явный выбор формата, например, «{0: KB}» для принудительного форматирования в килобайтах. Но я собираюсь оставить это в этом.
Я также оставляю свой первоначальный пост ниже, поскольку эти двое предпочитают не использовать API форматирования ...
100 способов убрать кошку, но вот мой подход - добавление метода расширения к типу int:
public static class IntToBytesExtension
{
private const int PRECISION = 2;
private static IList<string> Units;
static IntToBytesExtension()
{
Units = new List<string>(){
"B", "KB", "MB", "GB", "TB"
};
}
/// <summary>
/// Formats the value as a filesize in bytes (KB, MB, etc.)
/// </summary>
/// <param name="bytes">This value.</param>
/// <returns>Filesize and quantifier formatted as a string.</returns>
public static string ToBytes(this int bytes)
{
double pow = Math.Floor((bytes>0 ? Math.Log(bytes) : 0) / Math.Log(1024));
pow = Math.Min(pow, Units.Count-1);
double value = (double)bytes / Math.Pow(1024, pow);
return value.ToString(pow==0 ? "F0" : "F" + PRECISION.ToString()) + " " + Units[(int)pow];
}
}
С этим расширением в вашей сборке, чтобы отформатировать размер файла, просто используйте оператор вроде (1234567) .ToBytes ()
Следующий тест MbUnit проясняет, как выглядит вывод:
[Test]
public void CanFormatFileSizes()
{
Assert.AreEqual("128 B", (128).ToBytes());
Assert.AreEqual("1.00 KB", (1024).ToBytes());
Assert.AreEqual("10.00 KB", (10240).ToBytes());
Assert.AreEqual("100.00 KB", (102400).ToBytes());
Assert.AreEqual("1.00 MB", (1048576).ToBytes());
}
И вы можете легко изменить единицы измерения и точность в соответствии с вашими потребностями: -)