Vra

Is daar enige maklike manier om 'n klas wat gebruik maak IFormatProvider wat skryf uit 'n gebruiker-vriendelike lêer-grootte?

public static string GetFileSizeString(string filePath)
{
    FileInfo info = new FileInfo(@"c:\windows\notepad.exe");
    long size = info.Length;
    string sizeString = size.ToString(FileSizeFormatProvider); // This is where the class does its magic...
}

Dit moet lei tot snare geformateer iets soos " 2,5 MB ", " 3,9 GB ", " 670 grepe " en so aan.

Was dit nuttig?

Oplossing

Ek gebruik hierdie een, ek kry dit uit die web

public class FileSizeFormatProvider : IFormatProvider, ICustomFormatter
{
    public object GetFormat(Type formatType)
    {
        if (formatType == typeof(ICustomFormatter)) return this;
        return null;
    }

    private const string fileSizeFormat = "fs";
    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(fileSizeFormat))    
        {    
            return defaultFormat(format, arg, formatProvider);    
        }

        if (arg is string)    
        {    
            return defaultFormat(format, arg, formatProvider);    
        }

        Decimal size;

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

        string suffix;
        if (size > OneGigaByte)
        {
            size /= OneGigaByte;
            suffix = "GB";
        }
        else if (size > OneMegaByte)
        {
            size /= OneMegaByte;
            suffix = "MB";
        }
        else if (size > OneKiloByte)
        {
            size /= OneKiloByte;
            suffix = "kB";
        }
        else
        {
            suffix = " B";
        }

        string precision = format.Substring(2);
        if (String.IsNullOrEmpty(precision)) precision = "2";
        return String.Format("{0:N" + precision + "}{1}", size, suffix);

    }

    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();
    }

}

'n voorbeeld van die gebruik sou wees:

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

Krediet vir http://flimflan.com/blog/FileSizeFormatProvider.aspx

Daar is 'n probleem met toString (), dit verwag 'n NumberFormatInfo tipe wat IFormatProvider maar die NumberFormatInfo klas implemente verseël :(

As jy 'C # 3,0 jy 'n uitbreiding metode kan gebruik om die resultaat wat jy wil te kry:

public static class ExtensionMethods
{
    public static string ToFileSize(this long l)
    {
        return String.Format(new FileSizeFormatProvider(), "{0:fs}", l);
    }
}

Jy kan dit gebruik soos hierdie.

long l = 100000000;
Console.WriteLine(l.ToFileSize());

Hoop dit help.

Ander wenke

OK Ek is nie van plan om dit te draai as 'n formaat verskaffer maar eerder as die wiel weer uitvind daar is 'n Win32 API oproep om 'n grootte string gebaseer op verskaf grepe wat ek baie keer gebruik het in verskeie aansoeke formaat.

[DllImport("Shlwapi.dll", CharSet = CharSet.Auto)]
public static extern long StrFormatByteSize( long fileSize, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder buffer, int bufferSize );

So ek dink jy moet in staat wees om 'n diensverskaffer saam te stel met behulp van wat as die kern omskakeling kode.

Hier is 'n skakel om die MSDN spec vir StrFormatByteSize.

Ek besef nou dat jy eintlik is vra vir iets wat sal werk met String.Format () - ek dink ek moes die vraag twee keer lees voordat jy; -)

Ek hou nie van die oplossing waar jy moet uitdruklik slaag in 'n formaat verskaffer elke keer - van wat ek kon versamel uit hierdie artikel , die beste manier om dit te benader, is om te implementeer 'n filesize tipe, die implementering van die IFormattable koppelvlak.

Ek gaan voort en geïmplementeer 'n struct dat hierdie koppelvlak ondersteun, en wat uit 'n heelgetal kan gooi. In my eie-lêer wat verband hou APIs, sal ek my .FileSize eiendomme terug te keer 'n filesize byvoorbeeld.

Hier is die kode:

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];
    }
}

En 'n eenvoudige Eenheid Toets wat toon hoe dit werk:

    [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");
    }

Soos jy kan sien, die filesize tipe kan nou korrek geformateer, en dit is ook moontlik om die aantal desimale spesifiseer, asook die toepassing van gereelde numeriese opmaak indien nodig.

Ek dink jy kan dit veel verder te voer, byvoorbeeld toelaat eksplisiete formaat seleksie, bv "{0: KB}" af te dwing opmaak in kilogrepe. Maar ek gaan om dit te verlaat op hierdie.

Ek is ook verlaat my aanvanklike post hieronder vir daardie twee verkies om nie die formatering API te gebruik ...


100 maniere om 'n kat vel, maar hier is my benadering - die toevoeging van 'n uitbreiding metode om die int type:

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];
    }
}

Met hierdie uitbreiding in jou gemeente, 'n filesize formaat, net gebruik om 'n stelling soos (1234567) .ToBytes ()

Die volgende MbUnit toets verduidelik presies wat die uitset lyk:

    [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());
    }

En jy kan maklik die eenhede en noukeurigheid aan alles verander by jou behoeftes: -)

Dit is die eenvoudigste implementering ek weet lêer groottes formaat:

public string SizeText
{
    get
    {
        var units = new[] { "B", "KB", "MB", "GB", "TB" };
        var index = 0;
        double size = Size;
        while (size > 1024)
        {
            size /= 1024;
            index++;
        }
        return string.Format("{0:2} {1}", size, units[index]);
    }
}

AANGESIEN Grootte is die ongeformatteerde lêergrootte in grepe.

Groete Christen

http://www.wpftutorial.net

My kode ... dankie vir Shaun Austin.

[DllImport("Shlwapi.dll", CharSet = CharSet.Auto)]
public static extern long StrFormatByteSize(long fileSize, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder buffer, int bufferSize);

public void getFileInfo(string filename)
{
    System.IO.FileInfo fileinfo = new FileInfo(filename);
    this.FileName.Text = fileinfo.Name;
    StringBuilder buffer = new StringBuilder();
    StrFormatByteSize(fileinfo.Length, buffer, 100);
    this.FileSize.Text = buffer.ToString();
}

sedert verskuiwing is 'n baie goedkoop operasie

public static string ToFileSize(this long size)
{
    if (size < 1024)
    {
        return (size).ToString("F0") + " bytes";
    }
    else if ((size >> 10) < 1024)
    {
        return (size/(float)1024).ToString("F1") + " KB";
    }
    else if ((size >> 20) < 1024)
    {
        return ((size >> 10) / (float)1024).ToString("F1") + " MB";
    }
    else if ((size >> 30) < 1024)
    {
        return ((size >> 20) / (float)1024).ToString("F1") + " GB";
    }
    else if ((size >> 40) < 1024)
    {
        return ((size >> 30) / (float)1024).ToString("F1") + " TB";
    }
    else if ((size >> 50) < 1024)
    {
        return ((size >> 40) / (float)1024).ToString("F1") + " PB";
    }
    else
    {
        return ((size >> 50) / (float)1024).ToString("F0") + " EB";
    }
}

Ek benodig 'n weergawe wat gebruik kan word gelokaliseerde vir verskillende kulture (desimaal skeier, "byte" vertaling) en ondersteuning vir alle moontlike binêre voorvoegsels (tot Exa). Hier is 'n voorbeeld wat toon hoe om dit te gebruik:

// force "en-US" culture for tests
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(1033); 

// Displays "8.00 EB"
Console.WriteLine(FormatFileSize(long.MaxValue)); 

// Use "fr-FR" culture. Displays "20,74 ko", o is for "octet"
Console.WriteLine(FormatFileSize(21234, "o", null, CultureInfo.GetCultureInfo(1036)));

En hier is die kode:

    /// <summary>
    /// Converts a numeric value into a string that represents the number expressed as a size value in bytes, kilobytes, megabytes, gigabytes, terabytes, petabytes or exabytes, depending on the size
    /// </summary>
    /// <param name="size">The size.</param>
    /// <returns>
    /// The number converted.
    /// </returns>
    public static string FormatFileSize(long size)
    {
        return FormatFileSize(size, null, null, null);
    }

    /// <summary>
    /// Converts a numeric value into a string that represents the number expressed as a size value in bytes, kilobytes, megabytes, gigabytes, terabytes, petabytes or exabytes, depending on the size
    /// </summary>
    /// <param name="size">The size.</param>
    /// <param name="byteName">The string used for the byte name. If null is passed, "B" will be used.</param>
    /// <param name="numberFormat">The number format. If null is passed, "N2" will be used.</param>
    /// <param name="formatProvider">The format provider. May be null to use current culture.</param>
    /// <returns>The number converted.</returns>
    public static string FormatFileSize(long size, string byteName, string numberFormat, IFormatProvider formatProvider)
    {
        if (size < 0)
            throw new ArgumentException(null, "size");

        if (byteName == null)
        {
            byteName = "B";
        }

        if (string.IsNullOrEmpty(numberFormat))
        {
            numberFormat = "N2";
        }

        const decimal K = 1024;
        const decimal M = K * K;
        const decimal G = M * K;
        const decimal T = G * K;
        const decimal P = T * K;
        const decimal E = P * K;

        decimal dsize = size;

        string suffix = null;
        if (dsize >= E)
        {
            dsize /= E;
            suffix = "E";
        }
        else if (dsize >= P)
        {
            dsize /= P;
            suffix = "P";
        }
        else if (dsize >= T)
        {
            dsize /= T;
            suffix = "T";
        }
        else if (dsize >= G)
        {
            dsize /= G;
            suffix = "G";
        }
        else if (dsize >= M)
        {
            dsize /= M;
            suffix = "M";
        }
        else if (dsize >= K)
        {
            dsize /= K;
            suffix = "k";
        }
        if (suffix != null)
        {
            suffix = " " + suffix;
        }
        return string.Format(formatProvider, "{0:" + numberFormat + "}" + suffix + byteName, dsize);
    }

Hier is 'n uitbreiding met meer presisie:

    public static string FileSizeFormat(this long lSize)
    {
        double size = lSize;
        int index = 0;
        for(; size > 1024; index++)
            size /= 1024;
        return size.ToString("0.000 " + new[] { "B", "KB", "MB", "GB", "TB" }[index]);          
    }

'n Domain benadering kan hier gevind word: https : //github.com/Corniel/Qowaiv/blob/master/src/Qowaiv/IO/StreamSize.cs

Die StreamSize struct is 'n voorstelling van 'n stroom grootte, kan jy beide outomatiese formaat met die behoorlike uitbreiding, maar ook om te spesifiseer dat jy dit wil hê in KB / MB of wat ook al. Dit het 'n baie voordele, nie net omdat jy die uitleg uit die boks te kry, dit help ook om jou 'n beter modelle te maak, want dit is voor die hand liggend as wat die eiendom of die gevolg van 'n metode verteenwoordig 'n stroom grootte. Dit het ook 'n uitbreiding op lêergrootte:. GetStreamSize (hierdie File Info lêer)

Kort notasie

  • nuwe StreamSize (8900) .ToString ( "s") => 8900b
  • nuwe StreamSize (238900) .ToString ( "s") => 238.9kb
  • nuwe StreamSize (238900) .ToString ( "S") => 238,9 KG
  • nuwe StreamSize (238900) .ToString ( "0.000,00 S") => 0.238,90 KG

Full notasie

  • nuwe StreamSize (8900) .ToString ( "0.0 f") => 8900,0 byte
  • nuwe StreamSize (238900) .ToString ( "0 f") => 234 kilogreep
  • nuwe StreamSize (1238900) .ToString ( "0.00 F") => 1.24 Megabyte

Custom

  • nuwe StreamSize (8900) .ToString ( "0.0 KB") => 8,9 k
  • nuwe StreamSize (238900) .ToString ( "0.0 MB") => 0.2 MB
  • nuwe StreamSize (1238900) .ToString ( "#, ## 0.00 kilogreep") => 1,239.00 kilogreep
  • nuwe StreamSize (1238900) .ToString ( "#, ## 0") => 1238900

Daar is 'n NuGet-pakket, sodat jy net kan gebruik dat 'n mens: https: //www.nuget org / pakkette / Qowaiv

Ek het Eduardo se antwoord geneem en dit gekombineer met 'n soortgelyke voorbeeld van elders na addisionele opsies vir die uitleg gee.

public class FileSizeFormatProvider : IFormatProvider, ICustomFormatter
{
   public object GetFormat(Type formatType)
   {
      if (formatType == typeof(ICustomFormatter))
      {
         return this;
      }

      return null;
   }

   private const string fileSizeFormat = "FS";
   private const string kiloByteFormat = "KB";
   private const string megaByteFormat = "MB";
   private const string gigaByteFormat = "GB";
   private const string byteFormat = "B";
   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)
   {
      //
      // Ensure the format provided is supported
      //
      if (String.IsNullOrEmpty(format) || !(format.StartsWith(fileSizeFormat, StringComparison.OrdinalIgnoreCase) ||
                                            format.StartsWith(kiloByteFormat, StringComparison.OrdinalIgnoreCase) ||
                                            format.StartsWith(megaByteFormat, StringComparison.OrdinalIgnoreCase) ||
                                            format.StartsWith(gigaByteFormat, StringComparison.OrdinalIgnoreCase)))
      {
         return DefaultFormat(format, arg, formatProvider);
      }

      //
      // Ensure the argument type is supported
      //
      if (!(arg is long || arg is decimal || arg is int))
      {
         return DefaultFormat(format, arg, formatProvider);
      }

      //
      // Try and convert the argument to decimal
      //
      Decimal size;

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

      //
      // Determine the suffix to use and convert the argument to the requested size
      //
      string suffix;

      switch (format.Substring(0, 2).ToUpper())
      {
         case kiloByteFormat:
            size = size / oneKiloByte;
            suffix = kiloByteFormat;
            break;
         case megaByteFormat:
            size = size / oneMegaByte;
            suffix = megaByteFormat;
            break;
         case gigaByteFormat:
            size = size / oneGigaByte;
            suffix = gigaByteFormat;
            break;
         case fileSizeFormat:
            if (size > oneGigaByte)
            {
               size /= oneGigaByte;
               suffix = gigaByteFormat;
            }
            else if (size > oneMegaByte)
            {
               size /= oneMegaByte;
               suffix = megaByteFormat;
            }
            else if (size > oneKiloByte)
            {
               size /= oneKiloByte;
               suffix = kiloByteFormat;
            }
            else
            {
               suffix = byteFormat;
            }
            break;
         default:
            suffix = byteFormat;
            break;
      }

      //
      // Determine the precision to use
      //
      string precision = format.Substring(2);

      if (String.IsNullOrEmpty(precision))
      {
         precision = "2";
      }

      return String.Format("{0:N" + precision + "}{1}", size, suffix);
   }

   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();
   }
}

As jy verander:

      if (String.IsNullOrEmpty(precision))
      {
         precision = "2";
      }

in

      if (String.IsNullOrEmpty(precision))
      {
        if (size < 10)
        {
           precision = "2";
        }
        else if (size < 100)
        {
            precision = "1";
        }
        else
        {
           precision = "0";
        }
      }

die resultate sonder bykomende presisie specific (so net 0: FS in plaas van 0: fs3). Sal begin om Win32 se StrFormatByteSize () naboots deur die aanpassing van presisie grootte

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top