当前位置:  开发笔记 > 编程语言 > 正文

文件大小格式提供程序

如何解决《文件大小格式提供程序》经验,为你挑选了5个好方法。

有没有简单的方法来创建一个使用的类 IFormatProvider它写出一个用户友好的文件大小?

public static string GetFileSizeString(string filePath)
{
    FileInfo info = new FileInfo(@"c:\windows\notepad.exe");
    long size = info.Length;
    string sizeString = size.ToString(FileSizeFormatProvider); // This is where the class does its magic...
}

它应该导致字符串格式化为" 2,5 MB "," 3,9 GB "," 670字节 "等等.



1> Eduardo Camp..:

我用这个,我从网上得到它

public class FileSizeFormatProvider : IFormatProvider, ICustomFormatter
{
    public object GetFormat(Type formatType)
    {
        if (formatType == typeof(ICustomFormatter)) return this;
        return null;
    }

    private const string fileSizeFormat = "fs";
    private const Decimal OneKiloByte = 1024M;
    private const Decimal OneMegaByte = OneKiloByte * 1024M;
    private const Decimal OneGigaByte = OneMegaByte * 1024M;

    public string Format(string format, object arg, IFormatProvider formatProvider)
    {    
        if (format == null || !format.StartsWith(fileSizeFormat))    
        {    
            return defaultFormat(format, arg, formatProvider);    
        }

        if (arg is string)    
        {    
            return defaultFormat(format, arg, formatProvider);    
        }

        Decimal size;

        try    
        {    
            size = Convert.ToDecimal(arg);    
        }    
        catch (InvalidCastException)    
        {    
            return defaultFormat(format, arg, formatProvider);    
        }

        string suffix;
        if (size > OneGigaByte)
        {
            size /= OneGigaByte;
            suffix = "GB";
        }
        else if (size > OneMegaByte)
        {
            size /= OneMegaByte;
            suffix = "MB";
        }
        else if (size > OneKiloByte)
        {
            size /= OneKiloByte;
            suffix = "kB";
        }
        else
        {
            suffix = " B";
        }

        string precision = format.Substring(2);
        if (String.IsNullOrEmpty(precision)) precision = "2";
        return String.Format("{0:N" + precision + "}{1}", size, suffix);

    }

    private static string defaultFormat(string format, object arg, IFormatProvider formatProvider)
    {
        IFormattable formattableArg = arg as IFormattable;
        if (formattableArg != null)
        {
            return formattableArg.ToString(format, formatProvider);
        }
        return arg.ToString();
    }

}

使用的一个例子是:

Console.WriteLine(String.Format(new FileSizeFormatProvider(), "File size: {0:fs}", 100));
Console.WriteLine(String.Format(new FileSizeFormatProvider(), "File size: {0:fs}", 10000));

http://flimflan.com/blog/FileSizeFormatProvider.aspx的积分

ToString()存在问题,它期望实现IFormatProvider的NumberFormatInfo类型,但NumberFormatInfo类是密封的:(

如果您使用的是C#3.0,则可以使用扩展方法获得所需的结果:

public static class ExtensionMethods
{
    public static string ToFileSize(this long l)
    {
        return String.Format(new FileSizeFormatProvider(), "{0:fs}", l);
    }
}

你可以像这样使用它.

long l = 100000000;
Console.WriteLine(l.ToFileSize());

希望这可以帮助.



2> Shaun Austin..:

好吧我不打算把它作为格式提供程序包装起来,而不是重新发明轮子,有一个Win32 api调用来根据我在各种应用程序中多次使用的提供字节格式化一个大小字符串.

[DllImport("Shlwapi.dll", CharSet = CharSet.Auto)]
public static extern long StrFormatByteSize( long fileSize, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder buffer, int bufferSize );

所以我想你应该能够将使用它作为核心转换代码的提供者放在一起.

这里有一个链接到MSDN规范的StrFormatByteSize.


请注意,此函数返回一个本地化字符串(数字分隔符可能会有所不同),这取决于您真正想要的是好还是坏.

3> mindplay.dk..:

我现在意识到你实际上是在寻找可以使用String.Format()的东西 - 我想我应该在发布之前读过两次问题;-)

我不喜欢每次都必须明确传入格式提供程序的解决方案 - 从我从本文中收集到的,最好的方法是实现FileSize类型,实现IFormattable接口.

我继续实现了一个支持这个接口的结构,可以从一个整数转换.在我自己的文件相关API中,我将使用我的.FileSize属性返回FileSize实例.

这是代码:

using System.Globalization;

public struct FileSize : IFormattable
{
    private ulong _value;

    private const int DEFAULT_PRECISION = 2;

    private static IList Units;

    static FileSize()
    {
        Units = new List(){
            "B", "KB", "MB", "GB", "TB"
        };
    }

    public FileSize(ulong value)
    {
        _value = value;
    }

    public static explicit operator FileSize(ulong value)
    {
        return new FileSize(value);
    }

    override public string ToString()
    {
        return ToString(null, null);
    }

    public string ToString(string format)
    {
        return ToString(format, null);
    }

    public string ToString(string format, IFormatProvider formatProvider)
    {
        int precision;

        if (String.IsNullOrEmpty(format))
            return ToString(DEFAULT_PRECISION);
        else if (int.TryParse(format, out precision))
            return ToString(precision);
        else
            return _value.ToString(format, formatProvider);
    }

    /// 
    /// Formats the FileSize using the given number of decimals.
    /// 
    public string ToString(int precision)
    {
        double pow = Math.Floor((_value > 0 ? Math.Log(_value) : 0) / Math.Log(1024));
        pow = Math.Min(pow, Units.Count - 1);
        double value = (double)_value / Math.Pow(1024, pow);
        return value.ToString(pow == 0 ? "F0" : "F" + precision.ToString()) + " " + Units[(int)pow];
    }
}

还有一个简单的单元测试,演示了它的工作原理:

    [Test]
    public void CanUseFileSizeFormatProvider()
    {
        Assert.AreEqual(String.Format("{0}", (FileSize)128), "128 B");
        Assert.AreEqual(String.Format("{0}", (FileSize)1024), "1.00 KB");
        Assert.AreEqual(String.Format("{0:0}", (FileSize)10240), "10 KB");
        Assert.AreEqual(String.Format("{0:1}", (FileSize)102400), "100.0 KB");
        Assert.AreEqual(String.Format("{0}", (FileSize)1048576), "1.00 MB");
        Assert.AreEqual(String.Format("{0:D}", (FileSize)123456), "123456");

        // You can also manually invoke ToString(), optionally with the precision specified as an integer:
        Assert.AreEqual(((FileSize)111111).ToString(2), "108.51 KB");
    }

如您所见,FileSize类型现在可以正确格式化,并且还可以指定小数位数,以及根据需要应用常规数字格式.

我想你可以更进一步,例如允许显式格式选择,例如"{0:KB}"强制格式化为千字节.但是我会把它留在这里.

我也离开了我的初始帖子,因为那两个人不想使用格式化API ...


皮肤猫的100种方法,但这是我的方法 - 在int类型中添加扩展方法:

public static class IntToBytesExtension
{
    private const int PRECISION = 2;

    private static IList Units;

    static IntToBytesExtension()
    {
        Units = new List(){
            "B", "KB", "MB", "GB", "TB"
        };
    }

    /// 
    /// Formats the value as a filesize in bytes (KB, MB, etc.)
    /// 
    /// This value.
    /// Filesize and quantifier formatted as a string.
    public static string ToBytes(this int bytes)
    {
        double pow = Math.Floor((bytes>0 ? Math.Log(bytes) : 0) / Math.Log(1024));
        pow = Math.Min(pow, Units.Count-1);
        double value = (double)bytes / Math.Pow(1024, pow);
        return value.ToString(pow==0 ? "F0" : "F" + PRECISION.ToString()) + " " + Units[(int)pow];
    }
}

在程序集中使用此扩展,要格式化文件大小,只需使用类似(1234567).ToBytes()的语句

以下MbUnit测试精确地阐明了输出的样子:

    [Test]
    public void CanFormatFileSizes()
    {
        Assert.AreEqual("128 B", (128).ToBytes());
        Assert.AreEqual("1.00 KB", (1024).ToBytes());
        Assert.AreEqual("10.00 KB", (10240).ToBytes());
        Assert.AreEqual("100.00 KB", (102400).ToBytes());
        Assert.AreEqual("1.00 MB", (1048576).ToBytes());
    }

您可以轻松地将单位和精度更改为适合您需要的任何内容:-)


我唯一看到的问题是扩展方法“ ToBytes”,我认为它可能与将int转换为字节的方法(如您所知“ byte”是C#中的数据类型)相混淆。最好将其重命名为其他名称,也许是“ AsByteCount”。否则,我认为两者都是好的解决方案。

4> 小智..:

这是我知道的格式化文件大小最简单的实现:

public string SizeText
{
    get
    {
        var units = new[] { "B", "KB", "MB", "GB", "TB" };
        var index = 0;
        double size = Size;
        while (size > 1024)
        {
            size /= 1024;
            index++;
        }
        return string.Format("{0:2} {1}", size, units[index]);
    }
}

而Size是未格式化的文件大小(以字节为单位).

问候基督徒

http://www.wpftutorial.net



5> ariso..:

我的代码...感谢Shaun Austin.

[DllImport("Shlwapi.dll", CharSet = CharSet.Auto)]
public static extern long StrFormatByteSize(long fileSize, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder buffer, int bufferSize);

public void getFileInfo(string filename)
{
    System.IO.FileInfo fileinfo = new FileInfo(filename);
    this.FileName.Text = fileinfo.Name;
    StringBuilder buffer = new StringBuilder();
    StrFormatByteSize(fileinfo.Length, buffer, 100);
    this.FileSize.Text = buffer.ToString();
}

推荐阅读
echo7111436
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有