문제
사용하는 클래스를 만드는 쉬운 방법이 있습니까? 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,5MB", "3,9GB", "670 바이트" 등등.
해결책
나는 이것을 사용한다, 나는 웹에서 그것을 얻는다
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/filesizeizeformatprovider.aspx
tostring ()에는 문제가 있습니다. iformatprovider를 구현하는 숫자 포르 틴포 유형을 기대하지만 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());
도움이 되었기를 바랍니다.
다른 팁
좋아, 나는 그것을 형식 공급자로 래핑하지 않을 것이지만 휠을 재창조하기보다는 다양한 응용 프로그램에서 여러 번 사용한 제공된 바이트를 기반으로 크기 문자열을 형식화하기위한 Win32 API 호출이 있습니다.
[DllImport("Shlwapi.dll", CharSet = CharSet.Auto)]
public static extern long StrFormatByteSize( long fileSize, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder buffer, int bufferSize );
따라서이를 핵심 변환 코드로 사용하여 제공자를 구성 할 수 있어야한다고 생각합니다.
여기에 있습니다 링크 strformatbytesize의 MSDN 사양에.
나는 당신이 실제로 String.format ()와 함께 작동하는 무언가를 요구하고 있다는 것을 알고 있습니다. 게시하기 전에 질문을 두 번 읽어야한다고 생각합니다 ;-)
나는 당신이 매번 형식 제공자로 명시 적으로 통과 해야하는 솔루션을 좋아하지 않습니다. 이 기사, 이에 접근하는 가장 좋은 방법은 파일 크기 유형을 구현하여 iformattable 인터페이스를 구현하는 것입니다.
나는이 인터페이스를 지원하고 정수에서 캐스트 할 수있는 구조물을 구현했습니다. 내 파일 관련 API에서 .filesize 속성에 파일 크기 인스턴스를 반환하도록합니다.
코드는 다음과 같습니다.
using System.Globalization;
public struct FileSize : IFormattable
{
private ulong _value;
private const int DEFAULT_PRECISION = 2;
private static IList<string> Units;
static FileSize()
{
Units = new List<string>(){
"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);
}
/// <summary>
/// Formats the FileSize using the given number of decimals.
/// </summary>
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");
}
보시다시피, 파일 크기 유형은 이제 올바르게 형식화 될 수 있으며, 소수의 수를 지정하고 필요한 경우 일반 숫자 형식을 적용 할 수도 있습니다.
예를 들어 명시 적 형식 선택 (예를 들어 {0 : kb})이 킬로바이트에서 형식을 강제로 제공하는 등 훨씬 더 나아갈 수 있다고 생각합니다. 그러나 나는 이것에 그것을 떠날 것입니다.
또한 두 사람이 서식 API를 사용하지 않는 것을 선호하는 두 가지에 대한 초기 게시물을 남겨두고 있습니다 ...
고양이를 피부하는 100 가지 방법이지만 여기에 내 접근 방식이 있습니다. int 유형에 확장 방법을 추가합니다.
public static class IntToBytesExtension
{
private const int PRECISION = 2;
private static IList<string> Units;
static IntToBytesExtension()
{
Units = new List<string>(){
"B", "KB", "MB", "GB", "TB"
};
}
/// <summary>
/// Formats the value as a filesize in bytes (KB, MB, etc.)
/// </summary>
/// <param name="bytes">This value.</param>
/// <returns>Filesize and quantifier formatted as a string.</returns>
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());
}
그리고 당신은 당신의 요구에 맞는 것에서 단위와 정밀도를 쉽게 변경할 수 있습니다 :-)
이것은 파일 크기를 형식화하기 위해 가장 간단한 구현입니다.
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]);
}
}
크기는 바이트의 형식화되지 않은 파일 크기입니다.
인사 기독교
내 코드 ... 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();
}
이동은 매우 저렴한 작업이기 때문에
public static string ToFileSize(this long size)
{
if (size < 1024)
{
return (size).ToString("F0") + " bytes";
}
else if ((size >> 10) < 1024)
{
return (size/(float)1024).ToString("F1") + " KB";
}
else if ((size >> 20) < 1024)
{
return ((size >> 10) / (float)1024).ToString("F1") + " MB";
}
else if ((size >> 30) < 1024)
{
return ((size >> 20) / (float)1024).ToString("F1") + " GB";
}
else if ((size >> 40) < 1024)
{
return ((size >> 30) / (float)1024).ToString("F1") + " TB";
}
else if ((size >> 50) < 1024)
{
return ((size >> 40) / (float)1024).ToString("F1") + " PB";
}
else
{
return ((size >> 50) / (float)1024).ToString("F0") + " EB";
}
}
다른 배양 (소수 분리기, "바이트"번역)을 위해 현지화 할 수있는 버전이 필요했고 가능한 모든 것을 지원했습니다. 이진 접두사 (EXA까지). 다음은 사용 방법을 보여주는 예입니다.
// force "en-US" culture for tests
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(1033);
// Displays "8.00 EB"
Console.WriteLine(FormatFileSize(long.MaxValue));
// Use "fr-FR" culture. Displays "20,74 ko", o is for "octet"
Console.WriteLine(FormatFileSize(21234, "o", null, CultureInfo.GetCultureInfo(1036)));
그리고 여기 코드가 있습니다.
/// <summary>
/// Converts a numeric value into a string that represents the number expressed as a size value in bytes, kilobytes, megabytes, gigabytes, terabytes, petabytes or exabytes, depending on the size
/// </summary>
/// <param name="size">The size.</param>
/// <returns>
/// The number converted.
/// </returns>
public static string FormatFileSize(long size)
{
return FormatFileSize(size, null, null, null);
}
/// <summary>
/// Converts a numeric value into a string that represents the number expressed as a size value in bytes, kilobytes, megabytes, gigabytes, terabytes, petabytes or exabytes, depending on the size
/// </summary>
/// <param name="size">The size.</param>
/// <param name="byteName">The string used for the byte name. If null is passed, "B" will be used.</param>
/// <param name="numberFormat">The number format. If null is passed, "N2" will be used.</param>
/// <param name="formatProvider">The format provider. May be null to use current culture.</param>
/// <returns>The number converted.</returns>
public static string FormatFileSize(long size, string byteName, string numberFormat, IFormatProvider formatProvider)
{
if (size < 0)
throw new ArgumentException(null, "size");
if (byteName == null)
{
byteName = "B";
}
if (string.IsNullOrEmpty(numberFormat))
{
numberFormat = "N2";
}
const decimal K = 1024;
const decimal M = K * K;
const decimal G = M * K;
const decimal T = G * K;
const decimal P = T * K;
const decimal E = P * K;
decimal dsize = size;
string suffix = null;
if (dsize >= E)
{
dsize /= E;
suffix = "E";
}
else if (dsize >= P)
{
dsize /= P;
suffix = "P";
}
else if (dsize >= T)
{
dsize /= T;
suffix = "T";
}
else if (dsize >= G)
{
dsize /= G;
suffix = "G";
}
else if (dsize >= M)
{
dsize /= M;
suffix = "M";
}
else if (dsize >= K)
{
dsize /= K;
suffix = "k";
}
if (suffix != null)
{
suffix = " " + suffix;
}
return string.Format(formatProvider, "{0:" + numberFormat + "}" + suffix + byteName, dsize);
}
다음은 더 정밀한 확장입니다.
public static string FileSizeFormat(this long lSize)
{
double size = lSize;
int index = 0;
for(; size > 1024; index++)
size /= 1024;
return size.ToString("0.000 " + new[] { "B", "KB", "MB", "GB", "TB" }[index]);
}
도메인 구동 접근 방식은 여기에서 찾을 수 있습니다. https://github.com/corniel/qowaiv/blob/master/src/qowaiv/io/streamsize.cs
스트림 크기 구조물은 스트림 크기의 표현이며, 올바른 확장 기능을 갖춘 자동으로 포맷 할 수있을뿐만 아니라 KB/MB 등으로 원하는 것을 지정할 수 있습니다. 이것은 상자에서 서식을 얻기 때문에 많은 장점이있을뿐만 아니라, 방법의 속성 또는 메소드 결과가 스트림 크기를 나타내는 것보다 더 나은 모델을 만드는 데 도움이됩니다. 또한 파일 크기에 대한 확장 기능이 있습니다 : getStreamSize (이 fileInfo 파일).
짧은 표기법
- New Streamsize (8900) .ToString ( "S") => 8900b
- New Streamsize (238900) .ToString ( "S") => 238.9KB
- New Streamsize (238900) .ToString ( "S") => 238.9 kb
- New Streamsize (238900) .ToString ( "0000.00 S") => 0238.90 KB
전체 표기법
- New Streamsize (8900) .ToString ( "0.0 F") => 8900.0 바이트
- New Streamsize (238900) .ToString ( "0 F") => 234 Kilobyte
- New Streamsize (1238900) .ToString ( "0.00 F") => 1.24 메가 바이트
관습
- New Streamsize (8900) .ToString ( "0.0 kb") => 8.9 kb
- New Streamsize (238900) .ToString ( "0.0 MB") => 0.2MB
- New Streamsize (1238900) .ToString ( "#, ## 0.00 킬로 바이트") => 1,239.00 Kilobyte
- New Streamsize (1238900) .ToString ( "#, ## 0") => 1,238,900
Nuget-Package가 있으므로 다음을 사용할 수 있습니다. https://www.nuget.org/packages/qowaiv
나는 Eduardo의 답변을 취하고 다른 곳에서 비슷한 예제와 결합하여 서식에 대한 추가 옵션을 제공했습니다.
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 string kiloByteFormat = "KB";
private const string megaByteFormat = "MB";
private const string gigaByteFormat = "GB";
private const string byteFormat = "B";
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)
{
//
// Ensure the format provided is supported
//
if (String.IsNullOrEmpty(format) || !(format.StartsWith(fileSizeFormat, StringComparison.OrdinalIgnoreCase) ||
format.StartsWith(kiloByteFormat, StringComparison.OrdinalIgnoreCase) ||
format.StartsWith(megaByteFormat, StringComparison.OrdinalIgnoreCase) ||
format.StartsWith(gigaByteFormat, StringComparison.OrdinalIgnoreCase)))
{
return DefaultFormat(format, arg, formatProvider);
}
//
// Ensure the argument type is supported
//
if (!(arg is long || arg is decimal || arg is int))
{
return DefaultFormat(format, arg, formatProvider);
}
//
// Try and convert the argument to decimal
//
Decimal size;
try
{
size = Convert.ToDecimal(arg);
}
catch (InvalidCastException)
{
return DefaultFormat(format, arg, formatProvider);
}
//
// Determine the suffix to use and convert the argument to the requested size
//
string suffix;
switch (format.Substring(0, 2).ToUpper())
{
case kiloByteFormat:
size = size / oneKiloByte;
suffix = kiloByteFormat;
break;
case megaByteFormat:
size = size / oneMegaByte;
suffix = megaByteFormat;
break;
case gigaByteFormat:
size = size / oneGigaByte;
suffix = gigaByteFormat;
break;
case fileSizeFormat:
if (size > oneGigaByte)
{
size /= oneGigaByte;
suffix = gigaByteFormat;
}
else if (size > oneMegaByte)
{
size /= oneMegaByte;
suffix = megaByteFormat;
}
else if (size > oneKiloByte)
{
size /= oneKiloByte;
suffix = kiloByteFormat;
}
else
{
suffix = byteFormat;
}
break;
default:
suffix = byteFormat;
break;
}
//
// Determine the precision to use
//
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();
}
}
변경하면 :
if (String.IsNullOrEmpty(precision))
{
precision = "2";
}
~ 안으로
if (String.IsNullOrEmpty(precision))
{
if (size < 10)
{
precision = "2";
}
else if (size < 100)
{
precision = "1";
}
else
{
precision = "0";
}
}
추가 정밀 지정자가없는 결과 (0 : FS3 대신 0 : FS)는 정밀도를 크기로 조정하여 Win32의 strformatbytesize ()를 모방하기 시작합니다.