[C#] FileSizeFormatProvider
От: der Igel Россия  
Дата: 28.11.06 19:03
Оценка: 113 (13)
Hello, All!

Специальный форматер для вывода размеров файлов (10КB, 1,5MB, etc).
Объединяя идеи Гайдара и Joshua Flanagan.

Использовать
class Program

{

    static void Main(string[] args)

    {

        Console.WriteLine(String.Format(new FileSizeFormatProvider(), "File size: {0:fs3}", 100));

        Console.WriteLine(String.Format(new FileSizeFormatProvider(), "File size: {0:fs}", 2000));

        Console.WriteLine(String.Format(new FileSizeFormatProvider(), "File size: {0:fs1}", 30000000));

        Console.WriteLine(String.Format(new FileSizeFormatProvider(), "File size: {0:fs}", 400000000000));

    }

}


Результат
File size: 100.000B
File size: 1.95KB
File size: 28.6MB
File size: 372.53GB


Исходник
using System;
using System.Text;

namespace Rsdn.Framework.Common
{
 public class FileSizeFormatProvider : IFormatProvider, ICustomFormatter
 {
  public object GetFormat(Type formatType)
  {
   if (typeof(ICustomFormatter).IsAssignableFrom(formatType))
    return this;

   return null;
  }

  private const string fileSizeFormat = "fs";
 
  private string[] letters = new string[] { "B", "KB", "MB", "GB", "TB", "PB" };

  public string Format(string format, object arg, IFormatProvider formatProvider)
  {
   if (format == null || !format.StartsWith(fileSizeFormat))
   {
    return defaultFormat(format, arg, formatProvider);
   }

   Decimal size;
   try
   {
    size = Convert.ToDecimal(arg);
   }
   catch (InvalidCastException)
   {
    return defaultFormat(format, arg, formatProvider);
   }

   byte i = 0;
   while ((size >= 1024) && (i < letters.Length - 1))
   {
    i++;
    size /= 1024;
   }

   string precision = format.Substring(2);
   if (String.IsNullOrEmpty(precision)) precision = "2";

   return String.Format("{0:N" + precision + "}{1}", size, letters[i]);

  }

  private static string defaultFormat(string format, object arg, IFormatProvider formatProvider)
  {
   IFormattable formattableArg = arg as IFormattable;
   if (formattableArg != null)
   {
    return formattableArg.ToString(format, formatProvider);
   }

   return arg.ToString();
  }
 }
}
Posted via RSDN NNTP Server 2.1 beta
Re: [C#] FileSizeFormatProvider
От: _FRED_ Черногория
Дата: 29.11.06 12:46
Оценка: +1
Здравствуйте, der Igel, Вы писали:

DI>Специальный форматер для вывода размеров файлов (10КB, 1,5MB, etc).

DI>Объединяя идеи Гайдара и Joshua Flanagan.

ИМХО, массив
DI>  private string[] letters = new string[] { "B", "KB", "MB", "GB", "TB", "PB" };

можно объявить как
     private static readonly string[] letters = new string[] { "B", "KB", "MB", "GB", "TB", "PB" };


и неплохо бы иметь открытое статическое свойство Default, которое позволит не создавать объект каждый раз

... << RSDN@Home 1.2.0 alpha rev. 665>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Re: [C#] FileSizeFormatProvider
От: nzeemin Россия http://nzeemin.livejournal.com/
Дата: 06.12.06 05:35
Оценка:
Здравствуйте, der Igel, Вы писали:

DI>Специальный форматер для вывода размеров файлов (10КB, 1,5MB, etc).


К этому еще прикрутить обозначения на разных языках и разный вид десятичной точки, в зависимости от используемой локали — и вообще будет конфетка...
Re: [C#] FileSizeFormatProvider
От: Anton Batenev Россия https://github.com/abbat
Дата: 08.12.06 08:13
Оценка:
Здравствуйте, der Igel, Вы писали:

DI>Hello, All!


DI>Специальный форматер для вывода размеров файлов (10КB, 1,5MB, etc).

DI>Объединяя идеи Гайдара и Joshua Flanagan.

А почему бы внутри не использовать банальный интероп для StrFormatByteSizeW — локаль будет автоматически учитываться без лишних телодвижений?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: [C#] FileSizeFormatProvider
От: der Igel Россия  
Дата: 08.12.06 08:29
Оценка:
Hello, Anton!

AB> А почему бы внутри не использовать банальный интероп для

AB> StrFormatByteSizeW — локаль будет автоматически учитываться без лишних
AB> телодвижений?

Во-первых, нас интересует чисто дотнетовское решение, этот вариант и на моно отлично работает.
А во-вторых, с интеропом я тоже пробовал, эта функция регулярно рушилась (но не всегда, что только хуже).
Может я конечно криво писал интеропную функцию, но...
  [DllImport("shlwapi.dll", EntryPoint="StrFormatByteSize", CharSet=CharSet.Auto)]
  protected static extern string StrFormatByteSize([In] long number, [Out] StringBuilder buffer, [In] int bufferSize);

  /// <summary>
  /// Converts a numeric value into a string that represents the number expressed as a size value in bytes, kilobytes, megabytes, or gigabytes, depending on the size.
  /// </summary>
  /// <param name="number">Numeric value to be converted.</param>
  /// <returns>Converted text value of numeric value.</returns>

  public static string BytesToString(long number)
  {
   StringBuilder buffer = new StringBuilder();
   return StrFormatByteSize(number, buffer, buffer.Capacity);
  }
Posted via RSDN NNTP Server 2.1 beta
Re[3]: [C#] FileSizeFormatProvider
От: Anton Batenev Россия https://github.com/abbat
Дата: 08.12.06 10:07
Оценка:
Здравствуйте, der Igel, Вы писали:

AB>> А почему бы внутри не использовать банальный интероп для

AB>> StrFormatByteSizeW — локаль будет автоматически учитываться без лишних
AB>> телодвижений?

DI>Во-первых, нас интересует чисто дотнетовское решение, этот вариант и на моно отлично работает.


Ясно. Просто это как-то не было оговорено.

DI>А во-вторых, с интеропом я тоже пробовал, эта функция регулярно рушилась (но не всегда, что только хуже).

DI>Может я конечно криво писал интеропную функцию, но...

Попытался воспроизвести у себя. Со StringBuilder действительно почему-то падает, но не регулярно, а точно на втором вызове. Проверил на другом примере (ниже). Минут 15 уже колбасит — полет нормальный.

[System.Runtime.InteropServices.DllImport("shlwapi.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
static extern string StrFormatByteSizeW
    (
        [System.Runtime.InteropServices.In]
        ulong qdw,

        [System.Runtime.InteropServices.Out]
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
        string pwszBuf,

        [System.Runtime.InteropServices.In]
        uint cchBuf
    );

public static string StrFormatByteSize(ulong value)
{
    string buf = "                          ";  // от балды
    return StrFormatByteSizeW(value, buf, (uint)buf.Length);
}

static void Main(string[] args)
{
    System.Random random = new System.Random();

    while (true)
    {
        ulong value = (ulong)random.Next();
        string result = StrFormatByteSize(value);
        System.Console.WriteLine("{0} = {1}", value, result);
        System.Threading.Thread.Sleep(10);
    }
}
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.