Làm cách nào để có được kích thước tệp có thể đọc được bằng chữ viết tắt byte bằng .NET?


Câu trả lời:


353

Đây không phải là cách hiệu quả nhất để làm điều đó, nhưng nó dễ đọc hơn nếu bạn không quen thuộc với toán học nhật ký và phải đủ nhanh cho hầu hết các kịch bản.

string[] sizes = { "B", "KB", "MB", "GB", "TB" };
double len = new FileInfo(filename).Length;
int order = 0;
while (len >= 1024 && order < sizes.Length - 1) {
    order++;
    len = len/1024;
}

// Adjust the format string to your preferences. For example "{0:0.#}{1}" would
// show a single decimal place, and no space.
string result = String.Format("{0:0.##} {1}", len, sizes[order]);

12
Tôi tin rằng bạn có thể sử dụng Math.Log để xác định thứ tự thay vì sử dụng vòng lặp while.
Francois Botha

12
Ngoài ra, KB là 1000 byte. 1024 byte là KiB .
Constantin

12
@Constantin tốt mà phụ thuộc vào HĐH? Windows vẫn đếm 1024 byte là 1 KB và 1 MB = 1024 KB, Cá nhân tôi muốn ném KiB ra khỏi cửa sổ và chỉ đếm mọi thứ bằng cách sử dụng 1024? ...
Peter

4
@Petoj nó không phụ thuộc vào HĐH, định nghĩa là không biết hệ điều hành. Từ Wikipedia:The unit was established by the International Electrotechnical Commission (IEC) in 1998 and has been accepted for use by all major standards organizations
ANeves

3
Tôi thích mã này vì nó dường như chạy nhanh hơn nhưng tôi đã sửa đổi nó một chút để cho phép các số thập phân khác nhau. Các số nhỏ hơn sẽ hiển thị tốt hơn 2 vị trí thập phân, ví dụ: 1,38 MB trong khi các số lớn hơn yêu cầu số thập phân ít hơn, ví dụ: 246k hoặc 23,5KB:
Myke Black

320

sử dụng Log để giải quyết vấn đề ....

static String BytesToString(long byteCount)
{
    string[] suf = { "B", "KB", "MB", "GB", "TB", "PB", "EB" }; //Longs run out around EB
    if (byteCount == 0)
        return "0" + suf[0];
    long bytes = Math.Abs(byteCount);
    int place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));
    double num = Math.Round(bytes / Math.Pow(1024, place), 1);
    return (Math.Sign(byteCount) * num).ToString() + suf[place];
}

Cũng trong c #, nhưng nên nhanh chóng chuyển đổi. Ngoài ra tôi làm tròn đến 1 chữ số thập phân để dễ đọc.

Về cơ bản Xác định số lượng vị trí thập phân trong Cơ sở 1024 và sau đó chia cho 1024 ^ số thập phân.

Và một số mẫu sử dụng và đầu ra:

Console.WriteLine(BytesToString(9223372036854775807));  //Results in 8EB
Console.WriteLine(BytesToString(0));                    //Results in 0B
Console.WriteLine(BytesToString(1024));                 //Results in 1KB
Console.WriteLine(BytesToString(2000000));              //Results in 1.9MB
Console.WriteLine(BytesToString(-9023372036854775807)); //Results in -7.8EB

Chỉnh sửa: Đã chỉ ra rằng tôi đã bỏ lỡ một math.floor, vì vậy tôi kết hợp nó. (Convert.ToInt32 sử dụng làm tròn, không cắt ngắn và đó là lý do tại sao Tầng là cần thiết.) Cảm ơn bạn đã nắm bắt.

Edit2: Có một vài ý kiến ​​về kích thước âm và kích thước 0 byte, vì vậy tôi đã cập nhật để xử lý 2 trường hợp đó.


7
Tôi muốn cảnh báo rằng trong khi câu trả lời này thực sự là một đoạn mã ngắn thì nó không được tối ưu hóa nhất. Tôi muốn bạn xem qua phương pháp được đăng bởi @humbads. Tôi đã chạy microtesting gửi 10 000 000 tệp được tạo ngẫu nhiên thông qua cả hai phương thức và điều này đưa ra con số rằng phương pháp của anh ấy nhanh hơn ~ 30%. Tôi đã làm thêm một số phương pháp của anh ấy tuy nhiên (bài tập & đúc không cần thiết). Hơn nữa, tôi đã chạy thử nghiệm với kích thước âm tính (khi bạn so sánh các tệp) trong khi phương pháp humbads xử lý hoàn hảo phương pháp Nhật ký này sẽ đưa ra một ngoại lệ!
IvanL

1
Đúng, bạn nên thêm Math.Abs ​​cho kích thước âm. Hơn nữa, mã không xử lý trường hợp nếu kích thước chính xác là 0.
dasheddot

Math.Abs, Math.Floor, Math.Log, Chuyển đổi thành số nguyên, Math.Round, Math.Pow, Math.Sign, Thêm, Nhân, Chia? Không phải hàng tấn toán học này chỉ tạo ra một đột biến lớn trên bộ xử lý. Điều này có lẽ chậm hơn mã @humbads
Jayson Ragasa

Thất bại cho double.MaxValue(nơi = 102)
BrunoLM

Hoạt động tuyệt vời! Để bắt chước cách các cửa sổ hoạt động (ít nhất là trên Windows 7 cuối cùng của tôi), hãy thay thế Math.Round bằng Math.Cading. Cảm ơn một lần nữa. Tôi thích giải pháp này.
H_He

101

Một phiên bản thử nghiệm và tối ưu hóa đáng kể của chức năng được yêu cầu được đăng ở đây:

Kích thước tệp có thể đọc được của con người C # - Chức năng được tối ưu hóa

Mã nguồn:

// Returns the human-readable file size for an arbitrary, 64-bit file size 
// The default format is "0.### XB", e.g. "4.2 KB" or "1.434 GB"
public string GetBytesReadable(long i)
{
    // Get absolute value
    long absolute_i = (i < 0 ? -i : i);
    // Determine the suffix and readable value
    string suffix;
    double readable;
    if (absolute_i >= 0x1000000000000000) // Exabyte
    {
        suffix = "EB";
        readable = (i >> 50);
    }
    else if (absolute_i >= 0x4000000000000) // Petabyte
    {
        suffix = "PB";
        readable = (i >> 40);
    }
    else if (absolute_i >= 0x10000000000) // Terabyte
    {
        suffix = "TB";
        readable = (i >> 30);
    }
    else if (absolute_i >= 0x40000000) // Gigabyte
    {
        suffix = "GB";
        readable = (i >> 20);
    }
    else if (absolute_i >= 0x100000) // Megabyte
    {
        suffix = "MB";
        readable = (i >> 10);
    }
    else if (absolute_i >= 0x400) // Kilobyte
    {
        suffix = "KB";
        readable = i;
    }
    else
    {
        return i.ToString("0 B"); // Byte
    }
    // Divide by 1024 to get fractional value
    readable = (readable / 1024);
    // Return formatted number with suffix
    return readable.ToString("0.### ") + suffix;
}

1
+1! Đơn giản hơn và thẳng tiến! Làm cho bộ xử lý làm toán dễ dàng và nhanh hơn!
Jayson Ragasa

FYI, bạn không sử dụng giá trị ở double readable = (i < 0 ? -i : i);bất cứ đâu để loại bỏ nó. một điều nữa, dàn diễn viên là redaundat
Royi Namir

Tôi đã loại bỏ các diễn viên, thêm ý kiến ​​và khắc phục sự cố với dấu hiệu tiêu cực.
khiêm tốn

Câu trả lời chính xác. Cảm ơn, tại sao không chỉ sử dụng Math.Abs?
kspearrin

1
(i <0? -i: i) nhanh hơn khoảng 15% so với Math.Abs. Đối với một triệu cuộc gọi, Math.Abs ​​chậm hơn 0,5 mili giây trên máy của tôi - 3,2 ms so với 3,7 ms.
humbads

72
[DllImport ( "Shlwapi.dll", CharSet = CharSet.Auto )]
public static extern long StrFormatByteSize ( 
        long fileSize
        , [MarshalAs ( UnmanagedType.LPTStr )] StringBuilder buffer
        , 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="filelength">The numeric value to be converted.</param>
/// <returns>the converted string</returns>
public static string StrFormatByteSize (long filesize) {
     StringBuilder sb = new StringBuilder( 11 );
     StrFormatByteSize( filesize, sb, sb.Capacity );
     return sb.ToString();
}

Từ: http://www.pinvoke.net/default.aspx/shlwapi/StrFormatByteSize.html


36
Tôi có thể là một người mới, nhưng sử dụng những khẩu súng khổng lồ như ghim để giết con vịt đó là một sự lạm dụng lớn.
Bart

27
Đây có phải là những gì explorer sử dụng? Nếu vậy, thì rất hữu ích để cho phép mọi người khớp với kích thước tệp bạn hiển thị cho họ với những gì trình thám hiểm hiển thị.
Andrew Backer

8
Và một cái không phát minh lại bánh xe
Matthew Lock

Không phải 11 ký tự là giới hạn không đổi và hơi thấp cho điều đó sao? Ý tôi là, các ngôn ngữ khác có thể sử dụng nhiều ký tự hơn cho từ viết tắt kích thước byte hoặc các kiểu định dạng khác.
Ray

1
@Bart phải mất một thời gian để các noobs học được sự khôn ngoan trong việc này: "Chúng ta nên quên đi những hiệu quả nhỏ, nói về 97% thời gian: tối ưu hóa sớm là gốc rễ của mọi tội lỗi" ubiquity.acm.org/article.cfm? id = 1513451
Khóa Matthew

22

Một cách nữa để tạo ra nó, không có bất kỳ loại vòng lặp nào và với sự hỗ trợ kích thước âm (có ý nghĩa đối với những thứ như deltas kích thước tệp):

public static class Format
{
    static string[] sizeSuffixes = {
        "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };

    public static string ByteSize(long size)
    {
        Debug.Assert(sizeSuffixes.Length > 0);

        const string formatTemplate = "{0}{1:0.#} {2}";

        if (size == 0)
        {
            return string.Format(formatTemplate, null, 0, sizeSuffixes[0]);
        }

        var absSize = Math.Abs((double)size);
        var fpPower = Math.Log(absSize, 1000);
        var intPower = (int)fpPower;
        var iUnit = intPower >= sizeSuffixes.Length
            ? sizeSuffixes.Length - 1
            : intPower;
        var normSize = absSize / Math.Pow(1000, iUnit);

        return string.Format(
            formatTemplate,
            size < 0 ? "-" : null, normSize, sizeSuffixes[iUnit]);
    }
}

Và đây là bộ thử nghiệm:

[TestFixture] public class ByteSize
{
    [TestCase(0, Result="0 B")]
    [TestCase(1, Result = "1 B")]
    [TestCase(1000, Result = "1 KB")]
    [TestCase(1500000, Result = "1.5 MB")]
    [TestCase(-1000, Result = "-1 KB")]
    [TestCase(int.MaxValue, Result = "2.1 GB")]
    [TestCase(int.MinValue, Result = "-2.1 GB")]
    [TestCase(long.MaxValue, Result = "9.2 EB")]
    [TestCase(long.MinValue, Result = "-9.2 EB")]
    public string Format_byte_size(long size)
    {
        return Format.ByteSize(size);
    }
}

19

Kiểm tra thư viện ByteSize . Đó là System.TimeSpancho byte!

Nó xử lý việc chuyển đổi và định dạng cho bạn.

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

Nó cũng không đại diện chuỗi và phân tích cú pháp.

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

5
Đó là thư viện của riêng bạn, phải không?
Larsenal

10
Không có gì xấu hổ trong một thư viện tiện dụng như thế này. :-)
Larsenal

13

Tôi thích sử dụng phương pháp sau (nó hỗ trợ tối đa terabyte, đủ cho hầu hết các trường hợp, nhưng nó có thể dễ dàng được mở rộng):

private string GetSizeString(long length)
{
    long B = 0, KB = 1024, MB = KB * 1024, GB = MB * 1024, TB = GB * 1024;
    double size = length;
    string suffix = nameof(B);

    if (length >= TB) {
        size = Math.Round((double)length / TB, 2);
        suffix = nameof(TB);
    }
    else if (length >= GB) {
        size = Math.Round((double)length / GB, 2);
        suffix = nameof(GB);
    }
    else if (length >= MB) {
        size = Math.Round((double)length / MB, 2);
        suffix = nameof(MB);
    }
    else if (length >= KB) {
        size = Math.Round((double)length / KB, 2);
        suffix = nameof(KB);
    }

    return $"{size} {suffix}";
}

Xin lưu ý rằng điều này được viết cho C # 6.0 (2015), vì vậy nó có thể cần một chút chỉnh sửa cho các phiên bản trước.


11
int size = new FileInfo( filePath ).Length / 1024;
string humanKBSize = string.Format( "{0} KB", size );
string humanMBSize = string.Format( "{0} MB", size / 1024 );
string humanGBSize = string.Format( "{0} GB", size / 1024 / 1024 );

Câu trả lời tốt. Sẽ có vấn đề khi kích thước tệp quá nhỏ, trong trường hợp này / 1024 trả về 0. Bạn có thể sử dụng loại phân số và cuộc gọi Math.Ceilinghoặc một cái gì đó.
nawfal

10

Đây là một câu trả lời ngắn gọn xác định đơn vị tự động.

public static string ToBytesCount(this long bytes)
{
    int unit = 1024;
    string unitStr = "b";
    if (bytes < unit) return string.Format("{0} {1}", bytes, unitStr);
    else unitStr = unitStr.ToUpper();
    int exp = (int)(Math.Log(bytes) / Math.Log(unit));
    return string.Format("{0:##.##} {1}{2}", bytes / Math.Pow(unit, exp), "KMGTPEZY"[exp - 1], unitStr);
}

"B" là cho bit, "B" là dành cho Byte và "KMGTPEZY" tương ứng cho kilo, mega, giga, tera, peta, exa, zetta và yotta

Người ta có thể mở rộng nó để đưa ISO / IEC80000 vào tài khoản:

public static string ToBytesCount(this long bytes, bool isISO = true)
{
    int unit = 1024;
    string unitStr = "b";
    if (!isISO) unit = 1000;
    if (bytes < unit) return string.Format("{0} {1}", bytes, unitStr);
    else unitStr = unitStr.ToUpper();
    if (isISO) unitStr = "i" + unitStr;
    int exp = (int)(Math.Log(bytes) / Math.Log(unit));
    return string.Format("{0:##.##} {1}{2}", bytes / Math.Pow(unit, exp), "KMGTPEZY"[exp - 1], unitStr);
}

1
cho tất cả mọi người tự hỏi tại sao có một osau KMGTPE: tiếng Pháp của nó ( byteoctettiếng Pháp). Đối với bất kỳ ngôn ngữ nào khác, chỉ cần thay thế obằngb
Max R.

7
string[] suffixes = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
int s = 0;
long size = fileInfo.Length;

while (size >= 1024)
{
    s++;
    size /= 1024;
}

string humanReadable = String.Format("{0} {1}", size, suffixes[s]);

Bạn nên kiểm tra: while (size> = 1024 && s <hậu tố. Độ dài).
TcKs

không ... một số nguyên có chữ ký 64 bit không thể vượt quá ZB ... đại diện cho các số 2 ^ 70.
bobwienholt

7
Vậy tại sao lại đưa vào YB?
cấu hình

Tôi thích câu trả lời này nhất cho bản thân mình, nhưng mọi người ở đây đưa vào các giải pháp thực sự hiệu quả thực sự, bạn nên sử dụng ca "size = size >> 10" nhanh hơn rất nhiều so với chia ... và tôi nghĩ rằng thật tốt khi có Thêm công cụ xác định Hy Lạp ở đó, bởi vì trong tương lai gần, chức năng DLR rõ ràng sẽ không cần "kích thước dài .." bạn có thể sử dụng cpu vector 128 bit hoặc thứ gì đó có thể chứa ZB và lớn hơn;)
RandomNickName42

4
Bitshifting hiệu quả hơn so với phân chia trong thời kỳ mã hóa C trên kim loại. Bạn đã thực hiện một thử nghiệm hoàn hảo trong .NET để xem bithift có thực sự hiệu quả hơn không? Cách đây không lâu, tôi đã xem xét trạng thái của xor-exchange và thấy nó thực sự chậm hơn trong .NET so với sử dụng biến tạm thời.
Pete

7

Nếu bạn đang cố gắng khớp kích thước như trong chế độ xem chi tiết của Windows Explorer, đây là mã bạn muốn:

[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
private static extern long StrFormatKBSize(
    long qdw,
    [MarshalAs(UnmanagedType.LPTStr)] StringBuilder pszBuf,
    int cchBuf);

public static string BytesToString(long byteCount)
{
    var sb = new StringBuilder(32);
    StrFormatKBSize(byteCount, sb, sb.Capacity);
    return sb.ToString();
}

Điều này sẽ không chỉ khớp chính xác với Explorer mà còn cung cấp các chuỗi được dịch cho bạn và khớp các khác biệt trong các phiên bản Windows (ví dụ: trong Win10, K = 1000 so với các phiên bản trước K = 1024).


Mã này không biên dịch, bạn cần xác định dll từ chức năng này đến từ đâu. Vì vậy, toàn bộ nguyên mẫu hàm có âm thanh như thế này: [DLLImport ("shlwapi.dll", CharSet = CharSet.Auto, SetLastError = true)] ); Hãy để tôi là người đầu tiên sẽ ủng hộ giải pháp này. Tại sao phải phát minh lại bánh xe nếu bánh xe đã được phát minh? Đây là cách tiếp cận điển hình của tất cả các lập trình viên C #, nhưng thật không may, C # không đạt được tất cả các mục tiêu mà C ++ đạt được.
TarmoPikaro

Và một lỗi nữa: Int64.MaxValue đạt 9.223.372.036.854.775.807, yêu cầu phân bổ kích thước bộ đệm 25+ - Tôi đã làm tròn nó thành 32 chỉ trong trường hợp (không phải 11 như trong mã demo ở trên).
TarmoPikaro

Cảm ơn @TarmoPikaro. Khi tôi sao chép từ mã làm việc của mình, tôi đã bỏ lỡ DLLImport. Cũng tăng kích thước bộ đệm theo khuyến nghị của bạn. Nắm bắt tốt!
Metalogic

cách tiếp cận ấn tượng
tbhaxor

Điều này chỉ hiển thị đơn vị KB. Ý tưởng là để hiển thị đơn vị lớn nhất tùy thuộc vào giá trị.
jstuardo

5

Hỗn hợp của tất cả các giải pháp :-)

    /// <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="fileSize">The numeric value to be converted.</param>
    /// <returns>The converted string.</returns>
    public static string FormatByteSize(double fileSize)
    {
        FileSizeUnit unit = FileSizeUnit.B;
        while (fileSize >= 1024 && unit < FileSizeUnit.YB)
        {
            fileSize = fileSize / 1024;
            unit++;
        }
        return string.Format("{0:0.##} {1}", fileSize, unit);
    }

    /// <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="fileInfo"></param>
    /// <returns>The converted string.</returns>
    public static string FormatByteSize(FileInfo fileInfo)
    {
        return FormatByteSize(fileInfo.Length);
    }
}

public enum FileSizeUnit : byte
{
    B,
    KB,
    MB,
    GB,
    TB,
    PB,
    EB,
    ZB,
    YB
}

4

Có một dự án nguồn mở có thể làm điều đó và hơn thế nữa.

7.Bits().ToString();         // 7 b
8.Bits().ToString();         // 1 B
(.5).Kilobytes().Humanize();   // 512 B
(1000).Kilobytes().ToString(); // 1000 KB
(1024).Kilobytes().Humanize(); // 1 MB
(.5).Gigabytes().Humanize();   // 512 MB
(1024).Gigabytes().ToString(); // 1 TB

http://humanizr.net/#bytesize

https://github.com/MehdiK/Humanizer


3

Giống như giải pháp của @ NET3. Sử dụng shift thay vì chia để kiểm tra phạm vi bytes, bởi vì phân chia tốn nhiều chi phí CPU hơn.

private static readonly string[] UNITS = new string[] { "B", "KB", "MB", "GB", "TB", "PB", "EB" };

public static string FormatSize(ulong bytes)
{
    int c = 0;
    for (c = 0; c < UNITS.Length; c++)
    {
        ulong m = (ulong)1 << ((c + 1) * 10);
        if (bytes < m)
            break;
    }

    double n = bytes / (double)((ulong)1 << (c * 10));
    return string.Format("{0:0.##} {1}", n, UNITS[c]);
}

2

Tôi giả sử bạn đang tìm kiếm "1,4 MB" thay vì "1468006 byte"?

Tôi không nghĩ rằng có một cách tích hợp để làm điều đó trong .NET. Bạn sẽ cần chỉ ra đơn vị nào là phù hợp và định dạng nó.

Chỉnh sửa: Đây là một số mã mẫu để làm điều đó:

http://www.codeproject.com/KB/cpp/formatsize.aspx


2

Làm thế nào về một số đệ quy:

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

Sau đó, bạn gọi nó:

return ReturnSize(size, string.Empty);

Tốt nhưng nó ăn CPU
kamalpreet

1

2 xu của tôi:

  • Tiền tố cho kilobyte là kB (chữ thường K)
  • Vì các chức năng này là dành cho mục đích trình bày, nên người ta phải cung cấp một nền văn hóa, ví dụ: string.Format(CultureInfo.CurrentCulture, "{0:0.##} {1}", fileSize, unit);
  • Tùy thuộc vào ngữ cảnh, một kilobyte có thể là 1000 hoặc 1024 byte . Điều tương tự cũng xảy ra với MB, GB, v.v.

3
Một kilobyte có nghĩa là 1000 byte ( wolframalpha.com/input/?i=kilobyte ), nó không phụ thuộc vào ngữ cảnh. Nó theo lịch sử phụ thuộc vào bối cảnh, như wikipedia nói, và nó đã thay đổi vào năm 1998 và sự thay đổi trên thực tế bắt đầu vào khoảng năm 2005 khi các ổ cứng terabyte khiến nó được chú ý. Thuật ngữ cho 1024 byte là kibibyte. Mã chuyển đổi chúng dựa trên văn hóa đang tạo ra thông tin không chính xác.
Tuyệt vời nhất

1

Một cách tiếp cận nữa, cho những gì nó có giá trị. Tôi thích giải pháp tối ưu hóa @humbads được tham chiếu ở trên, vì vậy đã sao chép nguyên tắc này, nhưng tôi đã thực hiện nó một chút khác biệt.

Tôi cho rằng nó có thể gây tranh cãi về việc liệu nó có phải là một phương thức mở rộng hay không (vì không phải tất cả các độ dài đều nhất thiết phải là kích thước byte), nhưng tôi thích chúng, và ở đâu đó tôi có thể tìm thấy phương thức khi tôi cần tiếp theo!

Về các đơn vị, tôi không nghĩ rằng mình đã từng nói 'Kibibyte' hay 'Mebibyte' trong cuộc sống của mình, và trong khi tôi nghi ngờ về các tiêu chuẩn được thi hành như vậy hơn là phát triển, tôi cho rằng về lâu dài sẽ tránh nhầm lẫn .

public static class LongExtensions
{
    private static readonly long[] numberOfBytesInUnit;
    private static readonly Func<long, string>[] bytesToUnitConverters;

    static LongExtensions()
    {
        numberOfBytesInUnit = new long[6]    
        {
            1L << 10,    // Bytes in a Kibibyte
            1L << 20,    // Bytes in a Mebibyte
            1L << 30,    // Bytes in a Gibibyte
            1L << 40,    // Bytes in a Tebibyte
            1L << 50,    // Bytes in a Pebibyte
            1L << 60     // Bytes in a Exbibyte
        };

        // Shift the long (integer) down to 1024 times its number of units, convert to a double (real number), 
        // then divide to get the final number of units (units will be in the range 1 to 1023.999)
        Func<long, int, string> FormatAsProportionOfUnit = (bytes, shift) => (((double)(bytes >> shift)) / 1024).ToString("0.###");

        bytesToUnitConverters = new Func<long,string>[7]
        {
            bytes => bytes.ToString() + " B",
            bytes => FormatAsProportionOfUnit(bytes, 0) + " KiB",
            bytes => FormatAsProportionOfUnit(bytes, 10) + " MiB",
            bytes => FormatAsProportionOfUnit(bytes, 20) + " GiB",
            bytes => FormatAsProportionOfUnit(bytes, 30) + " TiB",
            bytes => FormatAsProportionOfUnit(bytes, 40) + " PiB",
            bytes => FormatAsProportionOfUnit(bytes, 50) + " EiB",
        };
    }

    public static string ToReadableByteSizeString(this long bytes)
    {
        if (bytes < 0)
            return "-" + Math.Abs(bytes).ToReadableByteSizeString();

        int counter = 0;
        while (counter < numberOfBytesInUnit.Length)
        {
            if (bytes < numberOfBytesInUnit[counter])
                return bytesToUnitConverters[counter](bytes);
            counter++;
        }
        return bytesToUnitConverters[counter](bytes);
    }
}

0

Tôi sử dụng phương pháp mở rộng dài bên dưới để chuyển đổi thành chuỗi kích thước có thể đọc được của con người. Phương pháp này là triển khai C # của giải pháp Java cho cùng một câu hỏi được đăng trên Stack Overflow, tại đây .

/// <summary>
/// Convert a byte count into a human readable size string.
/// </summary>
/// <param name="bytes">The byte count.</param>
/// <param name="si">Whether or not to use SI units.</param>
/// <returns>A human readable size string.</returns>
public static string ToHumanReadableByteCount(
    this long bytes
    , bool si
)
{
    var unit = si
        ? 1000
        : 1024;

    if (bytes < unit)
    {
        return $"{bytes} B";
    }

    var exp = (int) (Math.Log(bytes) / Math.Log(unit));

    return $"{bytes / Math.Pow(unit, exp):F2} " +
           $"{(si ? "kMGTPE" : "KMGTPE")[exp - 1] + (si ? string.Empty : "i")}B";
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.