Frage

Gibt es eine einfache Möglichkeit, eine Klasse zu erstellen, die verwendet IFormatProvider , das aus einer benutzerfreundlichen Dateigröße schreibt?

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...
}

Es in Strings führen sollte so etwas wie " 2,5 MB ", " 3,9 GB ", " 670 Bytes " formatiert und so weiter.

War es hilfreich?

Lösung

ich dies verwenden, ich habe es aus dem Netz zu bekommen

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

}

ein Beispiel für die Verwendung wäre:

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

Credits für http://flimflan.com/blog/FileSizeFormatProvider.aspx

Es gibt ein Problem mit ToString (), es erwartet einen Number Typ, IFormatProvider aber die Number Klasse implementiert wird versiegelt :(

Wenn Sie mit C # 3.0 können Sie eine Erweiterungsmethode verwenden Sie das Ergebnis, das Sie erhalten möchten:

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

Sie können es wie folgt verwendet werden.

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

Hope, das hilft.

Andere Tipps

OK, ich werde es nicht einpacken als Format-Anbieter, sondern als das Rad neu zu erfinden, es gibt ein Win32-API-Aufruf eine Größe Zeichenfolge auf gelieferten Bytes basiert zu formatieren, dass ich viele Male in verschiedenen Anwendungen verwendet haben.

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

So stelle ich mir sollten Sie in der Lage sein, einen Anbieter, um gemeinsam mit, dass als Kern Conversion-Code.

Hier ist ein Link der MSDN-spec für StrFormatByteSize.

Ich weiß jetzt, dass Sie tatsächlich auf etwas zu fragen, die mit String.Format funktionieren würde () - Ich glaube, ich die Frage zweimal gelesen haben, sollten vor der Veröffentlichung; -)

Ich mag nicht die Lösung, wenn Sie explizit in einem Format-Provider jedes Mal passieren müssen - von dem, was ich von

Ich lasse auch meinen ersten Beitrag unten für die beide es vorziehen, nicht die Formatierung API verwenden ...


100 Möglichkeiten, die Haut eine Katze, aber hier ist mein Ansatz - eine Erweiterungsmethode zum int-Typ hinzufügen:

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

Mit dieser Erweiterung in Ihrer Assembly, eine Dateigröße zu formatieren, einfach eine Anweisung wie (1234567) .ToBytes ()

Der folgende MbUnit Test klärt genau das, was die Ausgabe wie folgt aussieht:

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

Und Sie können leicht die Einheiten und Präzision ändern, was auch immer für Ihre Anforderungen: -)

Mein Code ... Vielen Dank für 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();
}

Da Verschiebung ist ein sehr billiger Betrieb

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

Ich brauchte eine Version, die für verschiedene Kulturen (Dezimaltrennzeichens „Byte“ Übersetzung) lokalisiert werden können und Unterstützung für alle möglichen binäre Präfixe (bis zu Exa). Hier ist ein Beispiel, das zeigt, wie man es benutzt:

// 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)));

Und hier ist der Code:

    /// <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 ist eine Erweiterung mit mehr Präzision:

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

Eine Domain Driven Ansatz kann hier gefunden werden: https : //github.com/Corniel/Qowaiv/blob/master/src/Qowaiv/IO/StreamSize.cs

Die Struktur stream eine Darstellung einer Stromgröße ist, ermöglicht sowohl Sie mit der richtigen Erweiterung automatischer formatiert werden, sondern auch angeben, dass Sie es in KB / MB oder was auch immer wollen. Dies hat viele Vorteile hat, nicht nur, weil Sie die Formatierung aus dem Kasten heraus zu bekommen, hilft es Ihnen auch bessere Modelle zu machen, wie es als offensichtlich ist, dass das Eigentum oder das Ergebnis eines Verfahrens eine Stromgröße darstellt. Es hat auch eine Erweiterung auf Dateigröße:. GetStreamSize (diese Fileinfo-Datei)

Kurzschreibweise

  • new stream (8900) .ToString ( "s") => 8900b
  • new stream (238900) .ToString ( "s") => 238.9kb
  • new stream (238900) .ToString ( "S") => 238,9 kB
  • new stream (238900) .ToString ( "0000.00 S") => 0.238,90 kB

Voll Notation

  • new stream (8900) .ToString ( "0,0 f") => 8900,0 Byte
  • new stream (238900) .ToString ( "0 f") => 234 Kilobyte
  • new stream (1238900) .ToString ( "0.00 F") => 1,24 Megabyte

Benutzerdefinierte

  • new stream (8900) .ToString ( "0,0 kb") => 8,9 kb
  • new stream (238900) .ToString ( "0.0 MB") => 0.2 MB
  • new stream (1238900) .ToString ( "#, ## 0.00 Kilobyte") => 1.239,00 Kilobyte
  • new stream (1238900) .ToString ( "#, ## 0") => 1238900

Es gibt ein NuGet-Paket, so können Sie nur verwenden, dass ein: https: //www.nuget .org / packages / Qowaiv

Ich habe Eduardo Antwort und kombiniert es mit einem ähnlichen Beispiel aus anderen Ländern, um zusätzliche Optionen für die Formatierung übernommen.

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

Wenn Sie ändern:

      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 Ergebnisse ohne zusätzliche Genauigkeitsbezeichner (so nur 0: fs statt 0: FS3). Beginnt Win32 der StrFormatByteSize () durch Einstellung Präzision Größe zu imitieren

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top