144

.NETがこれを行うためのクリーンな方法を提供しているかどうか疑問に思っています:

int64 x = 1000000;
string y = null;
if (x / 1024 == 0) {
    y = x + " bytes";
}
else if (x / (1024 * 1024) == 0) {
    y = string.Format("{0:n1} KB", x / 1024f);
}

等...

4

26 に答える 26

228

これを行うためのかなり簡潔な方法は次のとおりです。

static readonly string[] SizeSuffixes = 
                   { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
static string SizeSuffix(Int64 value, int decimalPlaces = 1)
{
    if (decimalPlaces < 0) { throw new ArgumentOutOfRangeException("decimalPlaces"); }
    if (value < 0) { return "-" + SizeSuffix(-value, decimalPlaces); } 
    if (value == 0) { return string.Format("{0:n" + decimalPlaces + "} bytes", 0); }

    // mag is 0 for bytes, 1 for KB, 2, for MB, etc.
    int mag = (int)Math.Log(value, 1024);

    // 1L << (mag * 10) == 2 ^ (10 * mag) 
    // [i.e. the number of bytes in the unit corresponding to mag]
    decimal adjustedSize = (decimal)value / (1L << (mag * 10));

    // make adjustment when the value is large enough that
    // it would round up to 1000 or more
    if (Math.Round(adjustedSize, decimalPlaces) >= 1000)
    {
        mag += 1;
        adjustedSize /= 1024;
    }

    return string.Format("{0:n" + decimalPlaces + "} {1}", 
        adjustedSize, 
        SizeSuffixes[mag]);
}

そして、これが私が提案した元の実装です。これはわずかに遅いかもしれませんが、従うのは少し簡単です。

static readonly string[] SizeSuffixes = 
                  { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };

static string SizeSuffix(Int64 value, int decimalPlaces = 1)
{
    if (value < 0) { return "-" + SizeSuffix(-value, decimalPlaces); } 

    int i = 0;
    decimal dValue = (decimal)value;
    while (Math.Round(dValue, decimalPlaces) >= 1000)
    {
        dValue /= 1024;
        i++;
    }

    return string.Format("{0:n" + decimalPlaces + "} {1}", dValue, SizeSuffixes[i]);
}

Console.WriteLine(SizeSuffix(100005000L));

覚えておくべきことの1つ-SI表記では、「キロ」は通常小文字のkを使用しますが、大きな単位はすべて大文字を使用します。WindowsはKB、MB、GBを使用するため、上記のKBを使用しましたが、代わりにkBを検討することもできます。

于 2013-01-23T20:38:59.160 に答える
117

ByteSizeライブラリをチェックアウトします。System.TimeSpanバイト用です!

変換と書式設定を処理します。

var maxFileSize = ByteSize.FromKiloBytes(10);
maxFileSize.Bytes;
maxFileSize.MegaBytes;
maxFileSize.GigaBytes;

また、文字列の表現と解析も行います。

// ToString
ByteSize.FromKiloBytes(1024).ToString(); // 1 MB
ByteSize.FromGigabytes(.5).ToString();   // 512 MB
ByteSize.FromGigabytes(1024).ToString(); // 1 TB

// Parsing
ByteSize.Parse("5b");
ByteSize.Parse("1.55B");
于 2014-03-12T23:58:20.853 に答える
53

Extension methodsMath.Pow関数、およびを使用して解決しますEnums

public static class MyExtension
{
    public enum SizeUnits
    {
        Byte, KB, MB, GB, TB, PB, EB, ZB, YB
    }

    public static string ToSize(this Int64 value, SizeUnits unit)
    {
        return (value / (double)Math.Pow(1024, (Int64)unit)).ToString("0.00");
    }
}

次のように使用します。

string h = x.ToSize(MyExtension.SizeUnits.KB);
于 2014-03-29T16:32:08.267 に答える
43

他の誰もがメソッドを投稿しているので、私は通常これに使用する拡張メソッドを投稿すると考えました:

編集: int/long バリアントを追加し、copypasta のタイプミスを修正しました...

public static class Ext
{
    private const long OneKb = 1024;
    private const long OneMb = OneKb * 1024;
    private const long OneGb = OneMb * 1024;
    private const long OneTb = OneGb * 1024;

    public static string ToPrettySize(this int value, int decimalPlaces = 0)
    {
        return ((long)value).ToPrettySize(decimalPlaces);
    }

    public static string ToPrettySize(this long value, int decimalPlaces = 0)
    {
        var asTb = Math.Round((double)value / OneTb, decimalPlaces);
        var asGb = Math.Round((double)value / OneGb, decimalPlaces);
        var asMb = Math.Round((double)value / OneMb, decimalPlaces);
        var asKb = Math.Round((double)value / OneKb, decimalPlaces);
        string chosenValue = asTb > 1 ? string.Format("{0}Tb",asTb)
            : asGb > 1 ? string.Format("{0}Gb",asGb)
            : asMb > 1 ? string.Format("{0}Mb",asMb)
            : asKb > 1 ? string.Format("{0}Kb",asKb)
            : string.Format("{0}B", Math.Round((double)value, decimalPlaces));
        return chosenValue;
    }
}
于 2013-01-23T20:44:05.180 に答える
16

私はこれがすでに古いスレッドであることを知っています。しかし、誰かが解決策を探すかもし​​れません。そして、これが私が使用するものであり、最も簡単な方法です

public static string FormatFileSize(long bytes)
{
    var unit = 1024;
    if (bytes < unit) { return $"{bytes} B"; }

    var exp = (int)(Math.Log(bytes) / Math.Log(unit));
    return $"{bytes / Math.Pow(unit, exp):F2} {("KMGTPE")[exp - 1]}B";
}

フォルダのサイズを取得する (使用状況など)

public static long GetFolderSize(string path, string ext, bool AllDir)
{
    var option = AllDir ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
    return new DirectoryInfo(path).EnumerateFiles("*" + ext, option).Sum(file => file.Length);
}

使用例:

public static void TEST()
{
    string folder = @"C:\Users\User\Videos";

    var bytes = GetFolderSize(folder, "mp4", true); //or GetFolderSize(folder, "mp4", false) to get all single folder only
    var totalFileSize = FormatFileSize(bytes);
    Console.WriteLine(totalFileSize);
}
于 2020-07-02T14:04:04.553 に答える
7

最も投票された回答の短いバージョンには、TB 値に問題があります。

tb 値も処理できるように適切に調整し、ループを発生させず、負の値のエラー チェックを少し追加しました。これが私の解決策です:

static readonly string[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
static string SizeSuffix(long value, int decimalPlaces = 0)
{
    if (value < 0)
    {
        throw new ArgumentException("Bytes should not be negative", "value");
    }
    var mag = (int)Math.Max(0, Math.Log(value, 1024));
    var adjustedSize = Math.Round(value / Math.Pow(1024, mag), decimalPlaces);
    return String.Format("{0} {1}", adjustedSize, SizeSuffixes[mag]);
}
于 2013-12-28T13:39:59.277 に答える
5

いいえ。ほとんどの場合、それはかなりニッチなニーズであり、考えられるバリエーションが多すぎるためです。(「KB」、「Kb」、または「Ko」ですか?メガバイトは 1024 * 1024 バイトですか、それとも 1024 * 1000 バイトですか? -- はい、一部の場所ではそれが使用されています!)

于 2013-01-23T20:33:39.617 に答える
5

あなたのオプションよりも簡単に拡張できるオプションがありますが、ライブラリ自体には何も組み込まれていません。

private static List<string> suffixes = new List<string> { " B", " KB", " MB", " GB", " TB", " PB" };
public static string Foo(int number)
{
    for (int i = 0; i < suffixes.Count; i++)
    {
        int temp = number / (int)Math.Pow(1024, i + 1);
        if (temp == 0)
            return (number / (int)Math.Pow(1024, i)) + suffixes[i];
    }
    return number.ToString();
}
于 2013-01-23T20:35:02.407 に答える
4
    private string GetFileSize(double byteCount)
    {
        string size = "0 Bytes";
        if (byteCount >= 1073741824.0)
            size = String.Format("{0:##.##}", byteCount / 1073741824.0) + " GB";
        else if (byteCount >= 1048576.0)
            size = String.Format("{0:##.##}", byteCount / 1048576.0) + " MB";
        else if (byteCount >= 1024.0)
            size = String.Format("{0:##.##}", byteCount / 1024.0) + " KB";
        else if (byteCount > 0 && byteCount < 1024.0)
            size = byteCount.ToString() + " Bytes";

        return size;
    }

    private void btnBrowse_Click(object sender, EventArgs e)
    {
        if (openFile1.ShowDialog() == DialogResult.OK)
        {
            FileInfo thisFile = new FileInfo(openFile1.FileName);

            string info = "";

            info += "File: " + Path.GetFileName(openFile1.FileName);
            info += Environment.NewLine;
            info += "File Size: " + GetFileSize((int)thisFile.Length);

            label1.Text = info;
        }
    }

これも 1 つの方法です (数値 1073741824.0 は 1024*1024*1024 別名 GB からのものです)。

于 2014-08-06T06:59:50.253 に答える
3

NeverHopeless のエレガントなソリューションに基づく:

private static readonly KeyValuePair<long, string>[] Thresholds = 
{
    // new KeyValuePair<long, string>(0, " Bytes"), // Don't devide by Zero!
    new KeyValuePair<long, string>(1, " Byte"),
    new KeyValuePair<long, string>(2, " Bytes"),
    new KeyValuePair<long, string>(1024, " KB"),
    new KeyValuePair<long, string>(1048576, " MB"), // Note: 1024 ^ 2 = 1026 (xor operator)
    new KeyValuePair<long, string>(1073741824, " GB"),
    new KeyValuePair<long, string>(1099511627776, " TB"),
    new KeyValuePair<long, string>(1125899906842620, " PB"),
    new KeyValuePair<long, string>(1152921504606850000, " EB"),

    // These don't fit into a int64
    // new KeyValuePair<long, string>(1180591620717410000000, " ZB"), 
    // new KeyValuePair<long, string>(1208925819614630000000000, " YB") 
};

/// <summary>
/// Returns x Bytes, kB, Mb, etc... 
/// </summary>
public static string ToByteSize(this long value)
{
    if (value == 0) return "0 Bytes"; // zero is plural
    for (int t = Thresholds.Length - 1; t > 0; t--)
        if (value >= Thresholds[t].Key) return ((double)value / Thresholds[t].Key).ToString("0.00") + Thresholds[t].Value;
    return "-" + ToByteSize(-value); // negative bytes (common case optimised to the end of this routine)
}

過剰なコメントもあるかもしれませんが、今後の訪問で同じ間違いを繰り返さないように、私はそれらを残す傾向があります...

于 2018-02-09T14:06:37.103 に答える
2

いいえ。

しかし、このように実装できます。

    static double ConvertBytesToMegabytes(long bytes)
    {
    return (bytes / 1024f) / 1024f;
    }

    static double ConvertKilobytesToMegabytes(long kilobytes)
    {
    return kilobytes / 1024f;
    }

また、バイト単位のファイルサイズをメガバイトまたはギガバイトに正しく変換する方法も確認してください。

于 2013-01-23T20:34:59.043 に答える
2

C# 9.0リレーショナル パターン用に更新

public const long OneKB = 1024;

public const long OneMB = OneKB * OneKB;

public const long OneGB = OneMB * OneKB;

public const long OneTB = OneGB * OneKB;

public static string BytesToHumanReadable(ulong bytes)
{
    return bytes switch
    {
        (< OneKB) => $"{bytes}B",
        (>= OneKB) and (< OneMB) => $"{bytes / OneKB}KB",
        (>= OneMB) and (< OneGB) => $"{bytes / OneMB}MB",
        (>= OneGB) and (< OneTB) => $"{bytes / OneMB}GB",
        (>= OneTB) => $"{bytes / OneTB}"
        //...
    };
}
于 2021-06-12T04:38:25.767 に答える
1

私は JerKimballs ソリューションに行きました。ただし、これは確かに全体として論争の問題であることを追加/指摘したいと思います。私の研究では(他の理由で)、次の情報を思いつきました。

普通の人 (存在すると聞いたことがあります) がギガバイトについて話すとき、元のバイト数の 1000 の 3 乗 == ギガバイト数というメートル法を指します。ただし、もちろん、ウィキペディアにうまくまとめられている IEC / JEDEC 規格があります。1000 の x 乗ではなく、1024 です。メートル法と IEC の差がますます大きくなっています。たとえば、1 TB == 1 テラバイト メトリックは 1000 の 4 乗ですが、IEC では同様の数値を 1 TiB、テビバイトを 1024 の 4 乗と公式に呼んでいます。基準はメトリックであり、現在、内部使用のための私自身のアプリでは、ドキュメントの違いを説明しています. しかし、表示目的のために、メトリック以外は何も提供していません。私のアプリには関係ありませんが、内部的にはバイトのみを保存し、表示のために計算を行います。

補足として、.NetフレームワークのAFAIK(そして、その力に感謝して私はしばしば間違っています)が4.5の化身であっても、これについて内部的にどのライブラリにも何も含まれていないことは、ややつまらないと思います。ある種のオープン ソース ライブラリが、ある時点で NuGettable になることを期待する人もいるでしょうが、私はこれがちょっとした不満であることを認めます。一方、 System.IO.DriveInfo などもバイト (できるだけ長い) しか持たないため、かなり明確です。

于 2015-11-13T10:26:11.050 に答える
1

いくつかの再帰はどうですか:

private static string ReturnSize(double size, string sizeLabel)
{
  if (size > 1024)
  {
    if (sizeLabel.Length == 0)
      return ReturnSize(size / 1024, "KB");
    else if (sizeLabel == "KB")
      return ReturnSize(size / 1024, "MB");
    else if (sizeLabel == "MB")
      return ReturnSize(size / 1024, "GB");
    else if (sizeLabel == "GB")
      return ReturnSize(size / 1024, "TB");
    else
      return ReturnSize(size / 1024, "PB");
  }
  else
  {
    if (sizeLabel.Length > 0)
      return string.Concat(size.ToString("0.00"), sizeLabel);
    else
      return string.Concat(size.ToString("0.00"), "Bytes");
  }
}

次に、それを呼び出すことができます:

ReturnSize(size, string.Empty);
于 2017-10-18T08:07:26.130 に答える
0

どうですか:

public void printMB(uint sizekB)   
{
    double sizeMB = (double) sizekB / 1024;
    Console.WriteLine("Size is " + sizeMB.ToString("0.00") + "MB");
}

たとえば、次のように呼び出します

printMB(123456);

出力が得られます

"Size is 120,56 MB"
于 2014-03-29T15:56:21.073 に答える
0

https://github.com/logary/logary/blob/master/src/Logary/DataModel.fs#L832-L837

let scaleBytes (value : float) : float * string =
    let log2 x = log x / log 2.
    let prefixes = [| ""; "Ki"; "Mi"; "Gi"; "Ti"; "Pi" |] // note the capital K and the 'i'
    let index = int (log2 value) / 10
    1. / 2.**(float index * 10.),
sprintf "%s%s" prefixes.[index] (Units.symbol Bytes)

(免責事項: このコードは、リンク内のコードも含めて、私が書きました!)

于 2016-12-12T17:50:12.607 に答える