Transformer les tailles de fichier en représentation textuelle

Je construis sur le gestionnaire de fichiers en ligne. L’une des colonnes affichées est la taille du fichier, mais il s’agit toujours d’un nombre élevé d’octets. Je voudrais afficher la taille du fichier comme l’explorateur Windows, avec un nombre plus petit et l’unité appropriée, par exemple 5 MB au lieu de 5000000 .

Ce n’est pas du tout difficile pour moi de le faire, mais je me demandais si Windows avait une fonction intégrée pour le faire. Y a-t-il déjà quelque chose ou dois-je rouler moi-même?

    Voici deux variantes (elles ont besoin de Windows Vista) en C #:

     ... Console.WriteLine(FormatByteSize(1031023120)); // 983 MB Console.WriteLine(FormatByteSize2(1031023120, true)); // 1 006 859 KB ... 

    Notez que l’avantage (ou l’inconvénient selon que vous le voyez) de l’utilisation de Windows est que vous obtiendrez une version localisée (le cas échéant), en utilisant la culture de Shell / OS.

     public static ssortingng FormatByteSize2(long size, bool alwaysKb = false) { // Here, we use Windows Shell's size column definition and formatting // note although System.Size is defined as a UInt64, formatting doesn't support more than long.MaxValue... PSGetPropertyKeyFromName("System.Size", out var pk); var pv = new PROPVARIANT(size); var sb = new SsortingngBuilder(128); const int PDFF_ALWAYSKB = 4; PSFormatForDisplay(ref pk, pv, alwaysKb ? PDFF_ALWAYSKB : 0, sb, sb.Capacity); return sb.ToSsortingng(); } public static ssortingng FormatByteSize(long size) { // Here, we use use a Windows Shell API (probably the sames algorithm underneath) // It's much simpler, we only need to declare one StrFormatByteSizeW API var sb = new SsortingngBuilder(128); StrFormatByteSizeW(size, sb, sb.Capacity); return sb.ToSsortingng(); } [DllImport("shlwapi", CharSet = CharSet.Unicode)] private static extern IntPtr StrFormatByteSizeW(long qdw, [MarshalAs(UnmanagedType.LPWStr)] SsortingngBuilder pszBuf, int cchBuf); [DllImport("propsys", CharSet = CharSet.Unicode)] private static extern int PSFormatForDisplay( ref PROPERTYKEY propkey, PROPVARIANT pv, int pdfFlags, [MarshalAs(UnmanagedType.LPWStr)] SsortingngBuilder pszBuf, int cchBuf); [DllImport("propsys", CharSet = CharSet.Unicode)] private static extern int PSGetPropertyKeyFromName([MarshalAs(UnmanagedType.LPWStr)] ssortingng pszName, out PROPERTYKEY ppropkey); [StructLayout(LayoutKind.Sequential)] private struct PROPERTYKEY { public Guid fmtid; public int pid; } [StructLayout(LayoutKind.Sequential)] private class PROPVARIANT { // note this version of PROPVARIANT is far from being suited for all purposes... public short vt; short wReserved1; short wReserved2; short wReserved3; public long val; const short VT_UI8 = 21; public PROPVARIANT(long ul) { wReserved3 = wReserved2 = wReserved1 = 0; val = ul; vt = VT_UI8; } } 

    Je vois 3 variantes:

     function FormatFileSize(const ASize: UInt64; AKbMode: Boolean): UnicodeSsortingng; var PS: IPropertySystem; PD: IPropertyDescription; PV: TPropVariant; Flags: DWORD; Display: PWideChar; PUI: IPropertyUI; begin Result := ''; // Variant 1 if Succeeded(CoCreateInstance(CLSID_IPropertySystem, nil, CLSCTX_INPROC_SERVER, IPropertySystem, PS)) then begin if Succeeded(PS.GetPropertyDescription(PKEY_Size, IPropertyDescription, PD)) then begin PV.vt := VT_UI8; PV.uhVal.QuadPart := ASize; if AKbMode then Flags := PDFF_ALWAYSKB else Flags := PDFF_DEFAULT; if Succeeded(PD.FormatForDisplay(PV, Flags, Display)) then begin Result := Display; CoTaskMemFree(Display); end; PD := nil; end; PS := nil; end; if Result <> '' then Exit; // Variant 2 - Windows XP mode, can be replaced with Variant 3 if Succeeded(CoCreateInstance(CLSID_PropertiesUI, nil, CLSCTX_INPROC_SERVER, IPropertyUI, PUI)) then begin PV.vt := VT_UI8; PV.uhVal.QuadPart := ASize; SetLength(Result, 100); if Succeeded(PUI.FormatForDisplay(PKEY_Size.fmtid, PKEY_Size.pid, PV, PUIFFDF_DEFAULT, PWideChar(Result), Length(Result) + 1)) then Result := PWideChar(Result) else Result := ''; PUI := nil; end; if Result <> '' then Exit; // Variant 3 SetLength(Result, 100); if AKbMode then Result := StrFormatKBSizeW(ASize, PWideChar(Result), Length(Result)) else Result := StrFormatByteSizeW(ASize, PWideChar(Result), Length(Result)); end;