【问题标题】:Converting bytes to GB in C#?在 C# 中将字节转换为 GB?
【发布时间】:2009-08-07 00:27:37
【问题描述】:

我在重构一些旧代码时遇到了以下将字节转换为 GB 的代码。

decimal GB = KB / 1024 / 1024 / 1024;

有没有更好的方法来重构以下代码?

更新

我的意思是说字节到千兆字节。我提供了错误的信息。

【问题讨论】:

  • decimal GB = KB / 1024 / 1024; 会更好...
  • 除了额外的除法之外,编写的代码没有任何问题;它的意图非常清楚,没有不必要的冗长,也没有性能问题。为什么要重构它?
  • 我认为这很好,虽然我可能会 GB = bytes * 1E-9;
  • 很抱歉成为那个人,但那是千兆字节而不是千兆字节。

标签: c# refactoring


【解决方案1】:

我在这里开发了这种方法,适用于 TB。

private static string FormatBytes(long bytes)
{
    string[] Suffix = { "B", "KB", "MB", "GB", "TB" };
    int i;
    double dblSByte = bytes;
    for (i = 0; i < Suffix.Length && bytes >= 1024; i++, bytes /= 1024) 
    {
        dblSByte = bytes / 1024.0;
    }

    return String.Format("{0:0.##} {1}", dblSByte, Suffix[i]);
}

【讨论】:

  • 我同意@ktutnik 关于第二部分的看法!
  • 这是如何工作的?您在 if/else 中缺少返回类型
  • 是的,自从我上次放在这里之后,有人修改了我的代码。
  • 当字节数达到PB时,代码出现bug。
【解决方案2】:

如果精确的精度不重要,请使用双精度:

double gb = kb / 1048576D

同意 Pavel 的观点 - 实际上没有必要重构此代码...事实上,如果这是您的代码库中最大的问题,我认为您可能正在使用有史以来编写得最好的软件。

【讨论】:

  • +1 关于使用 double,但我认为原始实现的意图更清晰。
  • @Marc 可能。我认为 gb = kb... 部分是一个很好的线索:)
  • 您可以通过将值 1048576 声明为具有显示名称意图的常量来提高其可读性...
【解决方案3】:

原代码简洁,易读,变量名合理,自文档化;我不会改变它。

如果你绝对必须重构,你可以在数值类型上创建一组扩展方法:

public static double BytesToKilobytes(this Int32 bytes)
{
    return bytes / 1024d;
}
public static double BytesToMegabytes(this Int32 bytes)
{
    return bytes / 1024d / 1024d;
}
public static double KilobytesToBytes(this double kilobytes)
{
    return kilobytes * 1024d;
}

//You can then do something like:
double filesize = 32.5d;
double bytes = filesize.KilobytesToBytes();

但除非您的代码实际上只将字节转换为千字节等,否则所有这些实际上只会使 Intellisense 变得混乱而没有真正的收益。

【讨论】:

    【解决方案4】:
        /// <summary>
    /// Function to convert the given bytes to either Kilobyte, Megabyte, or Gigabyte
    /// </summary>
    /// <param name="bytes">Double -> Total bytes to be converted</param>
    /// <param name="type">String -> Type of conversion to perform</param>
    /// <returns>Int32 -> Converted bytes</returns>
    /// <remarks></remarks>
    public static double ConvertSize(double bytes, string type)
    {
        try
        {
            const int CONVERSION_VALUE = 1024;
            //determine what conversion they want
            switch (type)
            {
                case "BY":
                     //convert to bytes (default)
                     return bytes;
                case "KB":
                     //convert to kilobytes
                     return (bytes / CONVERSION_VALUE);
                case "MB":
                     //convert to megabytes
                     return (bytes / CalculateSquare(CONVERSION_VALUE));
                case "GB":
                     //convert to gigabytes
                     return (bytes / CalculateCube(CONVERSION_VALUE));
                default:
                     //default
                     return bytes;
              }
         }
         catch (Exception ex)
         {
             Console.WriteLine(ex.Message);
             return 0;
          }
    }
    
    /// <summary>
    /// Function to calculate the square of the provided number
    /// </summary>
    /// <param name="number">Int32 -> Number to be squared</param>
    /// <returns>Double -> THe provided number squared</returns>
    /// <remarks></remarks>
    public static double CalculateSquare(Int32 number)
    {
         return Math.Pow(number, 2);
    }
    
    
    /// <summary>
    /// Function to calculate the cube of the provided number
    /// </summary>
    /// <param name="number">Int32 -> Number to be cubed</param>
    /// <returns>Double -> THe provided number cubed</returns>
    /// <remarks></remarks>
    public static double CalculateCube(Int32 number)
    {
         return Math.Pow(number, 3);
    }
    
    //Sample Useage
    String Size = "File is " + ConvertSize(250222,"MB") + " Megabytes in size"
    

    【讨论】:

    • 您可以使用具有 2 个参数、数量和幂的 CalculatePower 来代替 CalculateSquare 和 CalculateCube。
    【解决方案5】:

    我个人会这样写:decimal GB = KB / (1024 * 1024); 但实际上没有必要按照编写的方式重构代码。

    【讨论】:

      【解决方案6】:

      嗯,这个公式是错误的(一千兆字节中只有大约一百万千字节,而不是一千字节),但除此之外,没关系。任何习惯使用这些数字的人都会知道这意味着什么。

      我要注意的一件事(我不知道这是否是 C# 的问题)是,如果 x 不是基本类型,编译器可能无法优化 x/1024/1024。使用 C 和整数,编译器很容易将其转换为“令人眼花缭乱的快速右移 20 位”指令。

      如果 decimal 是一个类而不是基本类型,编译器可能必须执行两次除法运算。这是否对速度有任何实际影响(或者甚至是否发生)超出了我的知识范围。

      我会考虑更改的一件事是实际的变量名称。它对编译后的代码没有真正的影响,但我更喜欢更长的变量名而不是缩写,所以我会选择kiloBytes/gigaBytes 或类似的东西。 KB/GB 很容易与常量混淆,具体取决于您的编码标准。

      【讨论】:

      • decimal 是内置类型,而不是类。但它也不支持位移,即使它们是有意义的。也许编译器可以在这种情况下使用它们,即使程序员不能。
      【解决方案7】:

      理论上,这更快(预先计算常数以进行乘法而不是除法)。它的使用频率可能不够重要,但以防万一。

      double const KbToGbFactor = 1d / 1024 /1024;
      
      double gb = kb * KbToGbFactor;
      

      【讨论】:

      • 我很确定这将在程序编译时得到优化。不过,这里是否需要 const 更多的是品味问题。
      • 我喜欢这个“清晰”的答案(在我看来),但不喜欢“优化”。呃 :-)
      【解决方案8】:

      我需要它,从 3rd 方组件字面量大小(例如“0 字节”、“1.1 MB”)转换为通用大小(以字节为单位)。所以我是这样用的:

              private static long UnformatBytes(string sizeInWords)
          {
              if(string.IsNullOrWhiteSpace(sizeInWords))
                  return -1;
      
              string size = sizeInWords.Split(' ').FirstOrDefault();
              double result;
              if (string.IsNullOrWhiteSpace(size) || !double.TryParse(size, out result))
              {
                  Debugger.Break();
                  return -1;
              }
      
              int pow;
      
              if (sizeInWords.IndexOf("byte", StringComparison.OrdinalIgnoreCase) > -1)
                  pow = 0;
              else if (sizeInWords.IndexOf("kb", StringComparison.OrdinalIgnoreCase) > -1)
                  pow = 1;
              else if (sizeInWords.IndexOf("mb", StringComparison.OrdinalIgnoreCase) > -1)
                  pow = 2;
              else if (sizeInWords.IndexOf("gb", StringComparison.OrdinalIgnoreCase) > -1)
                  pow = 3;
              else if (sizeInWords.IndexOf("tb", StringComparison.OrdinalIgnoreCase) > -1)
                  pow = 4;
              else
                  return -1;
      
              return System.Convert.ToInt64((result * Math.Pow(1024, pow)));
          }
      

      【讨论】:

        【解决方案9】:

        我写了一个小工具类来执行单位之间的转换,hth..

        #region StorageDifferential
        /// <summary>
        /// Converts between Base 2 or Base 10 storage units [TB, GB, MB, KB, Bytes]
        /// </summary>
        public enum Differential : int
        {
            /// <summary>
            /// Convert Bytes to Kilobytes
            /// </summary>
            ByteToKilo,
            /// <summary>
            /// Convert Bytes to Megabytes
            /// </summary>
            ByteToMega,
            /// <summary>
            /// Convert Bytes to Gigabytes
            /// </summary>
            ByteToGiga,
            /// <summary>
            /// Convert Bytes to Teraytes
            /// </summary>
            ByteToTera,
            /// <summary>
            /// Convert Kilobytes to Bytes
            /// </summary>
            KiloToByte,
            /// <summary>
            /// Convert Kilobytes to Megabytes
            /// </summary>
            KiloToMega,
            /// <summary>
            /// Convert Kilobytes to Gigabytes
            /// </summary>
            KiloToGiga,
            /// <summary>
            /// Convert Kilobytes to Terabytes
            /// </summary>
            KiloToTera,
            /// <summary>
            /// Convert Megabytes to Bytes
            /// </summary>
            MegaToByte,
            /// <summary>
            /// Convert Megabytes to Kilobytes
            /// </summary>
            MegaToKilo,
            /// <summary>
            /// Convert Megabytes to Gigabytes
            /// </summary>
            MegaToGiga,
            /// <summary>
            /// Convert Megabytes to Terabytes
            /// </summary>
            MegaToTera,
            /// <summary>
            /// Convert Gigabytes to Bytes
            /// </summary>
            GigaToByte,
            /// <summary>
            /// Convert Gigabytes to Kilobytes
            /// </summary>
            GigaToKilo,
            /// <summary>
            /// Convert Gigabytes to Megabytes
            /// </summary>
            GigaToMega,
            /// <summary>
            /// Convert Gigabytes to Terabytes
            /// </summary>
            GigaToTerra,
            /// <summary>
            /// Convert Terabyte to Bytes
            /// </summary>
            TeraToByte,
            /// <summary>
            /// Convert Terabyte to Kilobytes
            /// </summary>
            TeraToKilo,
            /// <summary>
            /// Convert Terabytes to Megabytes
            /// </summary>
            TeraToMega,
            /// <summary>
            /// Convert Terabytes to Gigabytes
            /// </summary>
            TeraToGiga,
        }
        #endregion
        
        #region Storage Sizes
        /// <summary>
        /// Enumeration of recognized storage sizes [in Bytes]
        /// </summary>
        public enum StorageSizes : long
        {
            /// <summary>
            /// Base 10 Conversion
            /// </summary>
            KILOBYTE = 1000,
            MEGABYTE = 1000000,
            GIGABYTE = 1000000000,
            TERABYTE = 1000000000000,
            /// <summary>
            /// Base 2 Conversion
            /// </summary>
            KIBIBYTE = 1024,
            MEBIBYTE = 1048576,
            GIBIBYTE = 1073741824,
            TEBIBYTE = 1099511627776,
        }
        #endregion
        
        #region StorageBase
        /// <summary>
        /// Storage powers 10 based or 1024 based
        /// </summary>
        public enum StorageBase : int
        {
            /// <summary>
            /// 1024 Base power, Typically used in memory measurements
            /// </summary>
            BASE2,
            /// <summary>
            /// 10 Base power, Used in storage mediums like harddrives
            /// </summary>
            BASE10,
        }
        #endregion
        
        /// <summary>
        /// Convert between base 1024 storage units [TB, GB, MB, KB, Byte]
        /// </summary>
        public static class StorageConverter
        {
            /// <summary>
            /// Convert between base 1024 storage units [TB, GB, MB, KB, Byte]
            /// </summary>
            /// <param name="SizeDifferential">Storage conversion differential [enum]</param>
            /// <param name="UnitSize">Size as mutiple of unit type units [double]</param>
            /// <param name="BaseUnit">Size of the base power [enum]</param>
            /// <returns>Converted unit size [double]</returns>
            public static double Convert(Differential SizeDifferential, double UnitSize, StorageBase BaseUnit = StorageBase.BASE10)
            {
                if (UnitSize < 0.000000000001) return 0;
        
                double POWER1 = 1000;
                double POWER2 = 1000000;
                double POWER3 = 1000000000;
                double POWER4 = 1000000000000;
        
                if (BaseUnit == StorageBase.BASE2)
                {
                    POWER1 = 1024;
                    POWER2 = 1048576;
                    POWER3 = 1073741824;
                    POWER4 = 1099511627776;
                }
        
                switch (SizeDifferential)
                {
                    case Differential.ByteToKilo:
                        return UnitSize / POWER1;
                    case Differential.ByteToMega:
                        return UnitSize / POWER2;
                    case Differential.ByteToGiga:
                        return UnitSize / POWER3;
                    case Differential.ByteToTera:
                        return UnitSize / POWER4;
                    case Differential.KiloToByte:
                        return UnitSize * POWER1;
                    case Differential.KiloToMega:
                        return UnitSize / POWER1;
                    case Differential.KiloToGiga:
                        return UnitSize / POWER2;
                    case Differential.KiloToTera:
                        return UnitSize / POWER3;
                    case Differential.MegaToByte:
                        return UnitSize * POWER2;
                    case Differential.MegaToKilo:
                        return UnitSize * POWER1;
                    case Differential.MegaToGiga:
                        return UnitSize / POWER1;
                    case Differential.MegaToTera:
                        return UnitSize / POWER2;
                    case Differential.GigaToByte:
                        return UnitSize * POWER3;
                    case Differential.GigaToKilo:
                        return UnitSize * POWER2;
                    case Differential.GigaToMega:
                        return UnitSize * POWER1;
                    case Differential.GigaToTerra:
                        return UnitSize / POWER1;
                    case Differential.TeraToByte:
                        return UnitSize * POWER4;
                    case Differential.TeraToKilo:
                        return UnitSize * POWER3;
                    case Differential.TeraToMega:
                        return UnitSize * POWER2;
                    case Differential.TeraToGiga:
                        return UnitSize * POWER1;
                }
        
                return 0;
            }
        }
        

        【讨论】:

          【解决方案10】:

          这是对 JLopez 的好答案的一点改进。 这里可以选择是否有单位指示,公斤单位用小写的“k”写(大写的代表开尔文)

          //note: this is the JLopez answer!!
          /// <summary>
          /// Return size in human readable form
          /// </summary>
          /// <param name="bytes">Size in bytes</param>
          /// <param name="useUnit ">Includes measure unit (default: false)</param>
          /// <returns>Readable value</returns>
          public static string FormatBytes(long bytes, bool useUnit = false)
              {
                  string[] Suffix = { " B", " kB", " MB", " GB", " TB" };
                  double dblSByte = bytes;
                  int i;
                  for (i = 0; i < Suffix.Length && bytes >= 1024; i++, bytes /= 1024)
                  {
                      dblSByte = bytes / 1024.0;
                  }
                  return $"{dblSByte:0.##}{(useUnit ? Suffix[i] : null)}";
              }
          

          【讨论】:

            【解决方案11】:

            为了确保编译器预先计算除数:

            decimal GB = KB / (1024 * 1024);
            

            请注意,您实际上是在计算 GiB(千兆字节),而不是 GB(千兆字节)。如果你真的要计算 GB,那就是:

            decimal GB = KB / (1000 * 1000);
            

            【讨论】:

            • 一般使用gigabyte是指1024^3字节,mega代表1024^2,kilo代表1024。技术上可能不正确,但我不认为任何人(其他)这里介意。
            • 是的,尽管这个标准已经存在了十多年,但大多数人都不知道它,这就是我记下它的原因......
            • “标准”只是没有真正的标准,因为它改变了词语的共同含义,为共同的事物创造了新的词语。这就是为什么真的没有人接受这个标准,除了制定它的行业。
            • @BeowulfOF:你说的不是真的。我见过几个使用标准化单位的程序。这是一个真正的标准,由 IEC 定义并被 IEEE 和 CIPM 等几个大型标准化机构所接受。该标准没有改变单位的共同含义,因为没有共同含义。以“1.44 MB”软盘为例,其容量既不是 1.44 MB 也不是 1.44 MiB,而是 1.44 * 1024 * 1000 字节...
            【解决方案12】:
                public static string BytesToString(this long bytes, string format = "#,##0.00") {
                    var unitstr = new string[] { "B", "KB", "MB", "GB", "TB" };
                    var bytesd = Convert.ToDouble(bytes);
                    var unit = 0;
                    while (bytesd / 1024D > 1 && unit < unitstr.Length) {
                        unit++; bytesd /= 1024D;
                    }
                    return string.Format("{0:" + format + "}{1}", bytesd, unitstr[unit]);
                }
            

            【讨论】:

              【解决方案13】:
              #region AutoFileSize
                  public string AutoFileSize(long number)
                  {
                      double tmp = number;
                      string suffix = " B ";
                      if (tmp > 1024) { tmp = tmp / 1024; suffix = " KB"; }
                      if (tmp > 1024) { tmp = tmp / 1024; suffix = " MB"; }
                      if (tmp > 1024) { tmp = tmp / 1024; suffix = " GB"; }
                      if (tmp > 1024) { tmp = tmp / 1024; suffix = " TB"; }
                      return tmp.ToString("n") + suffix;
                  }
                  #endregion
              
              long number = (long)fu.PostedFile.ContentLength;
              

              【讨论】:

                猜你喜欢
                • 2023-01-25
                • 2012-08-02
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多