potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

C# バイトサイズを文字列に変換する関数群

バイトサイズを文字列に変化する関数群のサンプルコードです。Shell Lightweight Utility Functions(Microsoft)の仕様変更により、Windows 10からは1 KB = 1000バイトであることに注意してください。

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("{0}", ByteSizeFormatter.FormatKBSize(1024 * 6 + 56, 2));
            Console.WriteLine("{0}", ByteSizeFormatter.FormatByteSize(1024 * 6 + 256,
                ByteSizeFormatter.FormatByteFlags.RoundToNearestDisplayedDigit, 2));
        }
    }
    
    // バイトサイズをKB単位の文字列に変換する関数を提供します。
    public static partial class ByteSizeFormatter
    {
        [SuppressUnmanagedCodeSecurity]
        private static partial class NativeMethods
        {
            [DllImport("shlwapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
            public static extern IntPtr StrFormatKBSize(
                long qdw,
                [Out]StringBuilder pszBuf,
                uint cchBuf);
        }

        public static string FormatKBSize(long bytes, int expanding = 256)
        {
            var buffer = new StringBuilder(expanding);
            for (;;)
            {
                var s = NativeMethods.StrFormatKBSize(
                    bytes, buffer, (uint)buffer.Capacity);
                if (s == IntPtr.Zero)
                {
                    throw new Exception(
                        "StrFormatKBSize関数(shlwapi.dll)が失敗しました。",
                        new Win32Exception());
                }
                else if (buffer.Length + 1 < buffer.Capacity)
                {
                    return buffer.ToString();
                }
                buffer.Capacity += expanding;
            }
        }
    }

    // バイトサイズを既定の方法で文字列に変換する関数を提供します。
    public static partial class ByteSizeFormatter
    {
        [SuppressUnmanagedCodeSecurity]
        private static partial class NativeMethods
        {
            [DllImport("shlwapi.dll", SetLastError = false, CharSet = CharSet.Auto)]
            public static extern int StrFormatByteSizeEx(
                ulong ull,
                uint flags,
                [Out]StringBuilder pszBuf,
                uint cchBuf);
        }

        public static string FormatByteSize(
            ulong bytes,
            FormatByteFlags flags,
            int expanding = 256)
        {
            const int HR_WIN32_INSUFFICIENT_BUFFER = unchecked((int)0x8007007a);

            var buffer = new StringBuilder(expanding);
            for (;;)
            {
                var hr = NativeMethods.StrFormatByteSizeEx(
                    bytes, (uint)flags, buffer, (uint)buffer.Capacity);
                if (hr == 0)
                {
                    return buffer.ToString();
                }
                else if (hr != HR_WIN32_INSUFFICIENT_BUFFER)
                {
                    throw new Exception(
                        "StrFormatByteSizeEx関数(shlwapi.dll)が失敗しました。",
                        new Win32Exception(hr));
                }
                buffer.Capacity += expanding;
            }
        }

        public enum FormatByteFlags
        {
            RoundToNearestDisplayedDigit = 0x1,
            TruncateUndisplayedDecimalDigits = 0x2
        }
    }
}