ฉันจะรับขนาดไฟล์ที่มนุษย์สามารถอ่านได้เป็นตัวย่อไบต์โดยใช้. NET


279

ฉันจะรับขนาดไฟล์ที่มนุษย์สามารถอ่านได้เป็นตัวย่อไบต์โดยใช้. NET

ตัวอย่าง : ใช้อินพุต 7,326,629 และแสดง 6.98 MB


เกี่ยวกับstackoverflow.com/questions/128618/c-file-size-format-providerคืออะไร
Kiquenet

คำตอบ:


353

นี่ไม่ใช่วิธีที่มีประสิทธิภาพที่สุดในการทำ แต่อ่านง่ายขึ้นถ้าคุณไม่คุ้นเคยกับ log maths และควรเร็วพอสำหรับสถานการณ์ส่วนใหญ่

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
ฉันเชื่อว่าคุณสามารถใช้ Math.Log เพื่อกำหนดลำดับแทนที่จะใช้ลูป while
Francois Botha

12
นอกจากนี้ KB คือ 1000 ไบต์ 1024 ไบต์เป็นกิโลไบท์
Constantin

13
@ Constantin ดีขึ้นอยู่กับระบบปฏิบัติการหรือไม่ Windows ยังคงนับ 1024 ไบต์เป็น 1 KB และ 1 MB = 1024 KB โดยส่วนตัวแล้วฉันอยากจะโยน KiB ออกไปนอกหน้าต่างและนับทุกสิ่งด้วยการใช้ 1024 หรือไม่ ...
Peter

4
@ Petet มันไม่ได้ขึ้นอยู่กับระบบปฏิบัติการความหมายคือไม่เชื่อเรื่องพระเจ้า จากวิกิพีเดีย: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
ฉันชอบรหัสนี้เพราะดูเหมือนว่าจะทำงานได้เร็วขึ้น แต่ฉันแก้ไขมันเล็กน้อยเพื่ออนุญาตให้มีจำนวนทศนิยมที่แตกต่างกัน ตัวเลขที่เล็กกว่าจะแสดงตำแหน่งทศนิยม 2 ตำแหน่งได้ดีกว่าเช่น 1.38MB ในขณะที่ตัวเลขขนาดใหญ่ต้องการทศนิยมน้อยกว่าเช่น 246k หรือ 23.5KB:
Myke Black

321

ใช้บันทึกเพื่อแก้ปัญหา ....

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 # แต่ควรเป็นสแนปเพื่อแปลง อีกทั้งฉันปัดเศษทศนิยม 1 ตำแหน่งเพื่อให้สามารถอ่านได้

กำหนดจำนวนตำแหน่งทศนิยมใน 1024 ฐานโดยทั่วไปแล้วหารด้วย 1024 ^ ทศนิยม

และตัวอย่างบางส่วนของการใช้งานและเอาท์พุท:

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

แก้ไข: ถูกชี้ให้เห็นว่าฉันพลาด math.floor ดังนั้นฉันจึงรวมเข้าด้วยกัน (Convert.ToInt32 ใช้การปัดเศษไม่ใช่การตัดทอนและนั่นเป็นเหตุผลว่าทำไม Floor จึงจำเป็น) ขอบคุณสำหรับการจับ

แก้ไข 2: มีความคิดเห็นสองสามข้อเกี่ยวกับขนาดเชิงลบและขนาด 0 ไบต์ดังนั้นฉันจึงอัปเดตเพื่อจัดการ 2 กรณีเหล่านั้น


7
ฉันต้องการเตือนว่าแม้ว่าคำตอบนี้จะเป็นรหัสสั้น ๆ แต่ก็ไม่ได้รับการปรับปรุงมากที่สุด ฉันต้องการให้คุณดูวิธีการโพสต์โดย @humbads ฉันวิ่งแบบไมโครโค้ดเพื่อส่งไฟล์ขนาด 10,000,000 ไฟล์ที่สร้างขึ้นแบบสุ่มโดยใช้ทั้งสองวิธีและนี่จะแสดงตัวเลขที่วิธีการของเขาเร็วกว่า ~ 30% ฉันได้ทำความสะอาดเพิ่มเติมเกี่ยวกับวิธีการของเขาอย่างไรก็ตาม (มอบหมายที่ไม่จำเป็นและการคัดเลือก) ยิ่งกว่านั้นฉันทำการทดสอบด้วยขนาดลบ (เมื่อคุณเปรียบเทียบไฟล์) ในขณะที่วิธีการของ humbads ไม่มีที่ติประมวลผลวิธีการบันทึกนี้จะไม่มีข้อยกเว้น!
IvanL

1
ใช่คุณควรเพิ่ม Math.Abs ​​สำหรับขนาดเชิงลบ ยิ่งไปกว่านั้นรหัสไม่สามารถจัดการกับตัว
เรือนได้

Math.Abs, Math.Floor, Math.Log, แปลงเป็นจำนวนเต็ม, Math.Round, Math.Pow, Math.Sign, การเพิ่ม, การคูณ, การหาร? การคำนวณแบบตัน ๆ ไม่ใช่แค่ทำตัวขัดขวางให้กับโปรเซสเซอร์ นี่อาจช้ากว่า @humbads code
Jayson Ragasa

ล้มเหลวในการdouble.MaxValue(สถานที่ = 102)
BrunoLM

ใช้งานได้ดี! หากต้องการเลียนแบบวิธีการทำงานของ Windows (อย่างน้อยที่สุดใน Windows 7 ultimate ของฉัน) ให้แทนที่ Math.Round ด้วย Math.Ceiling ขอบคุณอีกครั้ง. ฉันชอบวิธีนี้
H_He

101

รุ่นที่ได้รับการทดสอบและปรับให้เหมาะสมอย่างมากของฟังก์ชั่นที่ร้องขอถูกโพสต์ที่นี่:

ขนาดไฟล์ C # ที่มนุษย์อ่านได้ - ฟังก์ชันที่ปรับให้เหมาะสม

รหัสแหล่งที่มา:

// 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! ง่ายขึ้นและตรงไปข้างหน้า! ทำให้โปรเซสเซอร์ทำคณิตศาสตร์ได้ง่ายและเร็วขึ้น!
Jayson Ragasa

FYI คุณไม่ได้ใช้ค่าในdouble readable = (i < 0 ? -i : i);ที่ใด ๆ ดังนั้นให้ลบออก อีกสิ่งหนึ่งนักแสดงคือ redaundat
Royi Namir

ฉันลบตัวละครเพิ่มความคิดเห็นและแก้ไขปัญหาด้วยเครื่องหมายลบ
humbads

คำตอบที่ดี ขอบคุณทำไมไม่เพียงใช้Math.Abs?
kspearrin

1
(i <0? -i: i) เร็วกว่า Math.Abs ​​ประมาณ 15% สำหรับหนึ่งล้านสาย Math.Abs ​​นั้นช้ากว่า 0.5 มิลลิวินาทีสำหรับเครื่องของฉัน - 3.2 ms เทียบกับ 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();
}

จาก: http://www.pinvoke.net/default.aspx/shlwapi/StrFormatByteSize.html


36
ฉันอาจเป็น noob แต่การใช้ปืนใหญ่ขนาดยักษ์เช่น pinvoke เพื่อฆ่าเป็ดนั่นเป็นวิธีที่ผิด
บาร์ต

27
นี่คือสิ่งที่นักสำรวจใช้หรือไม่ ถ้าเป็นเช่นนั้นก็มีประโยชน์อย่างยิ่งสำหรับการให้ผู้คนจับคู่ขนาดไฟล์ที่คุณแสดงให้พวกเขาเห็นด้วย
Andrew Backer

8
และอีกอันที่ไม่รวมตัวใหม่วงล้อ
Matthew Lock

อักขระ 11 ตัวมีขีด จำกัด คงที่และต่ำไปหรือไม่ ฉันหมายถึงภาษาอื่นอาจใช้อักขระมากขึ้นสำหรับตัวย่อขนาดไบต์หรือรูปแบบการจัดรูปแบบอื่น ๆ
Ray

1
@Bart ต้องใช้เวลาสักพักเพื่อที่ noobs จะได้เรียนรู้ภูมิปัญญาในเรื่องนี้: "เราควรลืมประสิทธิภาพเล็กน้อยพูดประมาณ 97% ของเวลา: การเพิ่มประสิทธิภาพก่อนวัยอันควรเป็นรากฐานของความชั่วร้ายทั้งหมด" ubiquity.acm.org/article.cfm? id = 1513451
Matthew Lock

22

อีกวิธีหนึ่งในการสกินโดยไม่มีลูปใด ๆ และด้วยการรองรับขนาดลบ (ทำให้รู้สึกถึงสิ่งต่าง ๆ เช่นเดลต้าขนาดไฟล์):

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

และนี่คือชุดทดสอบ:

[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

ชำระเงินห้องสมุด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");

5
มันเป็นห้องสมุดของคุณเองใช่ไหม
Larsenal

10
ไม่มีความละอายในห้องสมุดที่มีประโยชน์เช่นนี้ :-)
Larsenal

13

ฉันชอบใช้วิธีการต่อไปนี้ (รองรับสูงสุดเทราไบต์ซึ่งเพียงพอสำหรับกรณีส่วนใหญ่ แต่สามารถขยายได้อย่างง่ายดาย):

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

โปรดทราบว่าสิ่งนี้เขียนขึ้นสำหรับ C # 6.0 (2015) ดังนั้นอาจต้องแก้ไขเล็กน้อยสำหรับเวอร์ชันก่อนหน้า


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

คำตอบที่ดี. ควรมีปัญหาเมื่อขนาดไฟล์เล็กเกินไปซึ่งในกรณีนี้ / 1024 กลับเป็น 0 คุณสามารถใช้ประเภทและการโทรMath.Ceilingหรือเศษส่วน
nawfal

10

นี่คือคำตอบสั้น ๆ ที่กำหนดหน่วยโดยอัตโนมัติ

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" สำหรับบิต "B" สำหรับ Byte และ "KMGTPEZY" เป็นลำดับสำหรับกิโล, เมกะ, giga, tera, peta, exa, zetta และ yotta

หนึ่งสามารถขยายเพื่อนำISO / IEC80000เข้าบัญชี:

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
สำหรับทุกคนสงสัยว่าทำไมoKMGTPE ถึงเกิดขึ้นหลังจากนั้น: ภาษาฝรั่งเศส ( byteเป็นoctetภาษาฝรั่งเศส) สำหรับภาษาอื่น ๆ ให้แทนที่oด้วยb
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]);

คุณควรตรวจสอบ: ในขณะที่ (ขนาด> = 1024 && s <คำต่อท้ายความยาว)
TcKs

ไม่ ... เลขจำนวนเต็มแบบ 64 บิตไม่สามารถไปไกลกว่า ZB ... ซึ่งหมายถึงตัวเลข 2 ^ 70
bobwienholt

7
เหตุใดจึงต้องใส่ใน YB
กำหนดค่า

ฉันชอบคำตอบนี้ดีที่สุด แต่ทุกคนที่นี่ใส่โซลูชั่นที่มีประสิทธิภาพจริงๆคุณควรใช้ "size = size >> 10" shift เร็วกว่าการหาร ... และฉันคิดว่ามันดีนะ ตัวระบุพิเศษของกรีกที่นั่นเพราะในอนาคตอันใกล้ฟังก์ชั่น DLR ที่ใช้งานได้จะไม่ต้องการ "ขนาดยาว .. " คุณอาจอยู่ใน 128 บิตของ cpu แบบเวกเตอร์หรือบางอย่างที่สามารถเก็บ ZB และใหญ่กว่าได้)
RandomNickName42

4
Bitshifting นั้นมีประสิทธิภาพมากกว่าการหารในยุคของการเข้ารหัส C บนโลหะ คุณได้ทำการทดสอบ perf ใน. NET เพื่อดูว่า bitshift นั้นมีประสิทธิภาพมากกว่าหรือไม่? ไม่นานที่ผ่านมาฉันดูสถานะของ xor-swap และพบว่ามันช้าลงใน. NET กับการใช้ตัวแปรชั่วคราว
Pete

7

หากคุณพยายามจับคู่ขนาดตามที่แสดงในมุมมองรายละเอียดของ Windows Explorer นี่คือรหัสที่คุณต้องการ:

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

สิ่งนี้จะไม่เพียงตรงกับ Explorer อย่างแน่นอน แต่จะให้สตริงที่แปลสำหรับคุณและตรงกับความแตกต่างในรุ่น Windows (เช่นใน Win10, K = 1000 เทียบกับรุ่นก่อนหน้า K = 1024)


รหัสนี้ไม่ได้รวบรวมคุณจะต้องระบุ dll ที่ฟังก์ชั่นมาจาก ฟังก์ชั่นต้นแบบทั้งฟังดูเหมือนว่า: [DllImport ("shlwapi.dll", CharSet = CharSet.Auto, SetLastError = true)] สาธารณะคงที่ภายนอก StrFormatKBSize สาธารณะ (ยาว qdw, [MarshalAs (UnmanagedType.LPTStr)) ); ให้ฉันเป็นคนแรกที่จะสนับสนุนโซลูชันนี้ ทำไมต้องคิดค้นล้อใหม่ถ้าล้อถูกประดิษฐ์ขึ้นมาแล้ว? นี่เป็นวิธีการทั่วไปของโปรแกรมเมอร์ C # ทุกคน แต่น่าเสียดายที่ C # ไม่สามารถเข้าถึงเป้าหมายทั้งหมดที่ C ++ เข้าถึงได้
TarmoPikaro

และอีกหนึ่งข้อผิดพลาดเพิ่มเติม: Int64.MaxValue ถึง 9,223,372,036,854,775,807 ซึ่งต้องการการจัดสรรขนาดบัฟเฟอร์ 25+ - ฉันได้ปัดเป็น 32 ในกรณี (ไม่ใช่ 11 เหมือนในรหัสตัวอย่างด้านบน)
TarmoPikaro

ขอบคุณ @TarmoPikaro เมื่อฉันคัดลอกจากรหัสการทำงานของฉันฉันคิดถึง DllImport เพิ่มขนาดบัฟเฟอร์ตามคำแนะนำของคุณ จับดี!
Metalogic

วิธีการที่น่าประทับใจ
tbhaxor

แสดงหน่วย KB เท่านั้น แนวคิดคือการแสดงหน่วยที่ใหญ่ที่สุดขึ้นอยู่กับค่า
jstuardo

5

ส่วนผสมของโซลูชั่นทั้งหมด :-)

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

มีโครงการโอเพ่นซอร์สหนึ่งโครงการที่สามารถทำสิ่งนั้นได้และอีกมากมาย

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

ชอบวิธีแก้ปัญหาของ @ NET3 ใช้ shift แทนการหารเพื่อทดสอบช่วงbytesเนื่องจากการแบ่งใช้ต้นทุน CPU มากขึ้น

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

ฉันถือว่าคุณกำลังมองหา "1.4 MB" แทนที่จะเป็น "1468006 bytes"?

ฉันไม่คิดว่าจะมีวิธีการดังกล่าวในตัวใน. NET คุณจะต้องคิดออกว่าหน่วยใดเหมาะสมและจัดรูปแบบ

แก้ไข: นี่คือตัวอย่างรหัสที่จะทำเช่นนั้น:

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


2

เกี่ยวกับการสอบถามซ้ำ:

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

จากนั้นคุณเรียกมันว่า:

return ReturnSize(size, string.Empty);

ดี แต่กิน CPU
kamalpreet

1

2 เซนต์ของฉัน:

  • คำนำหน้าสำหรับกิโลไบต์คือ kB (ตัวพิมพ์เล็ก K)
  • เนื่องจากฟังก์ชั่นเหล่านี้มีวัตถุประสงค์เพื่อการนำเสนอเราจึงควรจัดหาวัฒนธรรมเช่น: string.Format(CultureInfo.CurrentCulture, "{0:0.##} {1}", fileSize, unit);
  • ทั้งนี้ขึ้นอยู่กับบริบทที่กิโลไบต์สามารถเป็นได้ทั้ง1000 หรือ 1024 ไบต์ เช่นเดียวกันสำหรับ MB, GB และอื่น ๆ

3
กิโลไบต์หมายถึง 1,000 ไบต์ ( wolframalpha.com/input/?i=kilobyte ) มันไม่ได้ขึ้นอยู่กับบริบท มันขึ้นอยู่กับบริบททางประวัติศาสตร์ตามที่วิกิพีเดียพูดและมันก็เปลี่ยนทางนิตินัยในปี 1998 และการเปลี่ยนแปลงตามความเป็นจริงเริ่มต้นขึ้นในปี 2005 เมื่อฮาร์ดไดรฟ์เทราไบต์นำมันมาสู่สาธารณชน คำสำหรับ 1024 ไบต์คือ kibibyte รหัสซึ่งเปลี่ยนพวกเขาตามวัฒนธรรมคือการผลิตข้อมูลที่ไม่ถูกต้อง
Superbest

1

อีกวิธีหนึ่งสำหรับสิ่งที่คุ้มค่า ฉันชอบ @humbads วิธีการแก้ปัญหาที่เพิ่มประสิทธิภาพการอ้างอิงข้างต้นดังนั้นได้คัดลอกหลักการ แต่ฉันใช้มันแตกต่างกันเล็กน้อย

ฉันคิดว่ามันเป็นที่ถกเถียงกันอยู่ว่าควรจะเป็นวิธีการต่อขยายหรือไม่ (เนื่องจากความยาวทั้งหมดไม่จำเป็นต้องเป็นขนาดไบต์) แต่ฉันชอบพวกเขาและเป็นที่ที่ฉันสามารถหาวิธีได้เมื่อฉันต้องการมันต่อไป!

เกี่ยวกับหน่วยฉันไม่คิดว่าฉันเคยพูดว่า 'Kibibyte' หรือ 'Mebibyte' ในชีวิตของฉันและในขณะที่ฉันไม่แน่ใจว่ามีการบังคับใช้ดังกล่าวมากกว่ามาตรฐานที่พัฒนาแล้วฉันคิดว่ามันจะหลีกเลี่ยงความสับสนในระยะยาว .

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

ฉันใช้วิธีการขยายแบบยาวด้านล่างเพื่อแปลงเป็นสตริงขนาดที่มนุษย์อ่านได้ วิธีนี้เป็นวิธีการดำเนินงาน C # ของการแก้ปัญหาของ Java คำถามเดียวกันนี้โพสต์บนกองมากเกิน, ที่นี่

/// <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";
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.