답변:
이를 수행하는 매우 간결한 방법은 다음과 같습니다.
static readonly string[] SizeSuffixes =
{ "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
static string SizeSuffix(Int64 value, int decimalPlaces = 1)
{
if (decimalPlaces < 0) { throw new ArgumentOutOfRangeException("decimalPlaces"); }
if (value < 0) { return "-" + SizeSuffix(-value); }
if (value == 0) { return string.Format("{0:n" + decimalPlaces + "} bytes", 0); }
// mag is 0 for bytes, 1 for KB, 2, for MB, etc.
int mag = (int)Math.Log(value, 1024);
// 1L << (mag * 10) == 2 ^ (10 * mag)
// [i.e. the number of bytes in the unit corresponding to mag]
decimal adjustedSize = (decimal)value / (1L << (mag * 10));
// make adjustment when the value is large enough that
// it would round up to 1000 or more
if (Math.Round(adjustedSize, decimalPlaces) >= 1000)
{
mag += 1;
adjustedSize /= 1024;
}
return string.Format("{0:n" + decimalPlaces + "} {1}",
adjustedSize,
SizeSuffixes[mag]);
}
그리고 제가 제안한 원래 구현은 약간 느릴 수 있지만 따라 가기가 조금 더 쉽습니다.
static readonly string[] SizeSuffixes =
{ "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
static string SizeSuffix(Int64 value, int decimalPlaces = 1)
{
if (value < 0) { return "-" + SizeSuffix(-value); }
int i = 0;
decimal dValue = (decimal)value;
while (Math.Round(dValue, decimalPlaces) >= 1000)
{
dValue /= 1024;
i++;
}
return string.Format("{0:n" + decimalPlaces + "} {1}", dValue, SizeSuffixes[i]);
}
Console.WriteLine(SizeSuffix(100005000L));
명심해야 할 한 가지는 SI 표기법에서 "kilo"는 일반적으로 소문자 k를 사용하는 반면 모든 큰 단위는 대문자를 사용합니다. Windows는 KB, MB, GB를 사용하므로 위의 KB를 사용했지만 대신 kB를 고려할 수 있습니다.
if (value == 0) { return "0"; }
함수 내부 에 체크 를 추가하기로 결정했습니다 .
체크 아웃 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");
다른 모든 사람들이 자신의 방법을 게시하기 때문에 일반적으로 사용하는 확장 방법을 게시 할 것이라고 생각했습니다.
편집 : int / long 변형 추가 ... 그리고 copypasta 오타 수정 ...
public static class Ext
{
private const long OneKb = 1024;
private const long OneMb = OneKb * 1024;
private const long OneGb = OneMb * 1024;
private const long OneTb = OneGb * 1024;
public static string ToPrettySize(this int value, int decimalPlaces = 0)
{
return ((long)value).ToPrettySize(decimalPlaces);
}
public static string ToPrettySize(this long value, int decimalPlaces = 0)
{
var asTb = Math.Round((double)value / OneTb, decimalPlaces);
var asGb = Math.Round((double)value / OneGb, decimalPlaces);
var asMb = Math.Round((double)value / OneMb, decimalPlaces);
var asKb = Math.Round((double)value / OneKb, decimalPlaces);
string chosenValue = asTb > 1 ? string.Format("{0}Tb",asTb)
: asGb > 1 ? string.Format("{0}Gb",asGb)
: asMb > 1 ? string.Format("{0}Mb",asMb)
: asKb > 1 ? string.Format("{0}Kb",asKb)
: string.Format("{0}B", Math.Round((double)value, decimalPlaces));
return chosenValue;
}
}
Extension methods
, Math.Pow
기능 및 Enums
다음을 사용하여 해결할 것입니다 .
public static class MyExtension
{
public enum SizeUnits
{
Byte, KB, MB, GB, TB, PB, EB, ZB, YB
}
public static string ToSize(this Int64 value, SizeUnits unit)
{
return (value / (double)Math.Pow(1024, (Int64)unit)).ToString("0.00");
}
}
다음과 같이 사용하십시오.
string h = x.ToSize(MyExtension.SizeUnits.KB);
가장 많이 득표 한 답변의 짧은 버전에는 TB 값에 문제가 있습니다.
tb 값도 처리하고 루프 없이도 적절하게 조정하고 음수 값에 대해 약간의 오류 검사를 추가했습니다. 내 해결책은 다음과 같습니다.
static readonly string[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
static string SizeSuffix(long value, int decimalPlaces = 0)
{
if (value < 0)
{
throw new ArgumentException("Bytes should not be negative", "value");
}
var mag = (int)Math.Max(0, Math.Log(value, 1024));
var adjustedSize = Math.Round(value / Math.Pow(1024, mag), decimalPlaces);
return String.Format("{0} {1}", adjustedSize, SizeSuffixes[mag]);
}
아니요. 대부분 틈새 시장이 필요하고 가능한 변형이 너무 많기 때문입니다. ( "KB", "Kb"또는 "Ko"입니까? 메가 바이트 1024 * 1024 바이트 또는 1024 * 1000 바이트입니까?-예, 일부 장소에서 사용합니다!)
다음은 확장하기 쉬운 옵션이지만 라이브러리 자체에 내장 된 옵션은 없습니다.
private static List<string> suffixes = new List<string> { " B", " KB", " MB", " GB", " TB", " PB" };
public static string Foo(int number)
{
for (int i = 0; i < suffixes.Count; i++)
{
int temp = number / (int)Math.Pow(1024, i + 1);
if (temp == 0)
return (number / (int)Math.Pow(1024, i)) + suffixes[i];
}
return number.ToString();
}
private string GetFileSize(double byteCount)
{
string size = "0 Bytes";
if (byteCount >= 1073741824.0)
size = String.Format("{0:##.##}", byteCount / 1073741824.0) + " GB";
else if (byteCount >= 1048576.0)
size = String.Format("{0:##.##}", byteCount / 1048576.0) + " MB";
else if (byteCount >= 1024.0)
size = String.Format("{0:##.##}", byteCount / 1024.0) + " KB";
else if (byteCount > 0 && byteCount < 1024.0)
size = byteCount.ToString() + " Bytes";
return size;
}
private void btnBrowse_Click(object sender, EventArgs e)
{
if (openFile1.ShowDialog() == DialogResult.OK)
{
FileInfo thisFile = new FileInfo(openFile1.FileName);
string info = "";
info += "File: " + Path.GetFileName(openFile1.FileName);
info += Environment.NewLine;
info += "File Size: " + GetFileSize((int)thisFile.Length);
label1.Text = info;
}
}
이것은 또한 그것을 수행하는 한 가지 방법입니다 (숫자 1073741824.0은 1024 * 1024 * 1024 일명 GB)
@Servy의 대답 은 훌륭하고 간결했습니다. 더 간단할까요?
private static string[] suffixes = new [] { " B", " KB", " MB", " GB", " TB", " PB" };
public static string ToSize(double number, int precision = 2)
{
// unit's number of bytes
const double unit = 1024;
// suffix counter
int i = 0;
// as long as we're bigger than a unit, keep going
while(number > unit)
{
number /= unit;
i++;
}
// apply precision and current suffix
return Math.Round(number, precision) + suffixes[i];
}
NeverHopeless의 우아한 솔루션을 기반으로 :
private static readonly KeyValuePair<long, string>[] Thresholds =
{
// new KeyValuePair<long, string>(0, " Bytes"), // Don't devide by Zero!
new KeyValuePair<long, string>(1, " Byte"),
new KeyValuePair<long, string>(2, " Bytes"),
new KeyValuePair<long, string>(1024, " KB"),
new KeyValuePair<long, string>(1048576, " MB"), // Note: 1024 ^ 2 = 1026 (xor operator)
new KeyValuePair<long, string>(1073741824, " GB"),
new KeyValuePair<long, string>(1099511627776, " TB"),
new KeyValuePair<long, string>(1125899906842620, " PB"),
new KeyValuePair<long, string>(1152921504606850000, " EB"),
// These don't fit into a int64
// new KeyValuePair<long, string>(1180591620717410000000, " ZB"),
// new KeyValuePair<long, string>(1208925819614630000000000, " YB")
};
/// <summary>
/// Returns x Bytes, kB, Mb, etc...
/// </summary>
public static string ToByteSize(this long value)
{
if (value == 0) return "0 Bytes"; // zero is plural
for (int t = Thresholds.Length - 1; t > 0; t--)
if (value >= Thresholds[t].Key) return ((double)value / Thresholds[t].Key).ToString("0.00") + Thresholds[t].Value;
return "-" + ToByteSize(-value); // negative bytes (common case optimised to the end of this routine)
}
댓글이 너무 많을 수도 있지만, 앞으로 방문 할 때 같은 실수를하지 않도록 남겨 두는 편입니다.
아니.
하지만 이렇게 구현할 수 있습니다.
static double ConvertBytesToMegabytes(long bytes)
{
return (bytes / 1024f) / 1024f;
}
static double ConvertKilobytesToMegabytes(long kilobytes)
{
return kilobytes / 1024f;
}
또한 바이트 단위의 파일 크기를 메가 또는 기가 바이트로 올바르게 변환하는 방법을 확인하십시오 .
여기에 대한 답변 중 일부를 훌륭하게 작동하는 두 가지 방법으로 결합했습니다. 아래의 두 번째 방법은 바이트 문자열 (예 : 1.5.1GB)에서 다시 바이트 (예 : 1621350140)를 long 유형 값으로 변환합니다. 나는 이것이 바이트를 문자열로 변환하고 다시 바이트로 변환하는 솔루션을 찾는 다른 사람들에게 유용하기를 바랍니다.
public static string BytesAsString(float bytes)
{
string[] suffix = { "B", "KB", "MB", "GB", "TB" };
int i;
double doubleBytes = 0;
for (i = 0; (int)(bytes / 1024) > 0; i++, bytes /= 1024)
{
doubleBytes = bytes / 1024.0;
}
return string.Format("{0:0.00} {1}", doubleBytes, suffix[i]);
}
public static long StringAsBytes(string bytesString)
{
if (string.IsNullOrEmpty(bytesString))
{
return 0;
}
const long OneKb = 1024;
const long OneMb = OneKb * 1024;
const long OneGb = OneMb * 1024;
const long OneTb = OneGb * 1024;
double returnValue;
string suffix = string.Empty;
if (bytesString.IndexOf(" ") > 0)
{
returnValue = float.Parse(bytesString.Substring(0, bytesString.IndexOf(" ")));
suffix = bytesString.Substring(bytesString.IndexOf(" ") + 1).ToUpperInvariant();
}
else
{
returnValue = float.Parse(bytesString.Substring(0, bytesString.Length - 2));
suffix = bytesString.ToUpperInvariant().Substring(bytesString.Length - 2);
}
switch (suffix)
{
case "KB":
{
returnValue *= OneKb;
break;
}
case "MB":
{
returnValue *= OneMb;
break;
}
case "GB":
{
returnValue *= OneGb;
break;
}
case "TB":
{
returnValue *= OneTb;
break;
}
default:
{
break;
}
}
return Convert.ToInt64(returnValue);
}
float.Parse
에 double
?
나는 이것이 이미 오래된 스레드라는 것을 알고 있습니다. 그러나 누군가는 해결책을 찾을 것입니다. 제가 사용하는 가장 쉬운 방법은 다음과 같습니다.
public static string FormatFileSize(long bytes)
{
var unit = 1024;
if (bytes < unit)
{
return $"{bytes} B";
}
var exp = (int)(Math.Log(bytes) / Math.Log(unit));
return $"{bytes / Math.Pow(unit, exp):F2} " +
$"{("KMGTPE")[exp - 1]}B";
}
나는 JerKimballs 솔루션으로 갔고 그것에 좋아요. 그러나 나는 이것이 실제로 전체적으로 논란의 문제라는 점을 덧붙이거나 지적하고 싶다. 내 연구에서 (다른 이유로) 다음 정보를 얻었습니다.
평범한 사람들 (나는 그들이 존재한다고 들었습니다)이 기가 바이트에 대해 말할 때, 그들은 1000의 원래 바이트 수 == 기가 바이트 수에서 3의 거듭 제곱 인 미터법을 말합니다. 그러나 물론 위키피디아에 잘 요약 된 IEC / JEDEC 표준이 있는데, 1000 대신 x의 거듭 제곱이 1024입니다. 물리적 저장 장치의 경우 (아마존과 같은 논리적이라고 생각합니다) 미터법과 IEC 간의 차이가 계속 증가하고 있습니다. 예를 들어 1TB == 1 테라 바이트 메트릭은 1000의 4 제곱이지만 IEC는 공식적으로 유사한 숫자를 1TiB, 테비 바이트는 1024의 4 제곱으로 간주합니다.하지만 아쉽게도 비 기술적 애플리케이션에서는 청중에 의해 이동) 표준은 메트릭이며 현재 내부 사용을위한 내 앱에서 문서의 차이점을 설명합니다. 그러나 표시 목적으로는 미터법 외에는 아무것도 제공하지 않습니다. 내부적으로는 내 앱과 관련이 없지만 바이트 만 저장하고 표시를 위해 계산을 수행합니다.
부수적으로 나는 .Net 프레임 워크 AFAIK (그리고 나는 4.5 화신에서도 내부적으로 이것에 대해 아무것도 포함하지 않는다는 것을 잘못 알고 있습니다. 누군가는 어떤 종류의 오픈 소스 라이브러리가 어떤 시점에서 NuGettable이 될 것이라고 기대할 수 있지만 이것은 작은 오해임을 인정합니다. 반면에 System.IO.DriveInfo 및 기타 항목에는 다소 명확한 바이트 만 있습니다.
public static class MyExtension
{
public static string ToPrettySize(this float Size)
{
return ConvertToPrettySize(Size, 0);
}
public static string ToPrettySize(this int Size)
{
return ConvertToPrettySize(Size, 0);
}
private static string ConvertToPrettySize(float Size, int R)
{
float F = Size / 1024f;
if (F < 1)
{
switch (R)
{
case 0:
return string.Format("{0:0.00} byte", Size);
case 1:
return string.Format("{0:0.00} kb", Size);
case 2:
return string.Format("{0:0.00} mb", Size);
case 3:
return string.Format("{0:0.00} gb", Size);
}
}
return ConvertToPrettySize(F, ++R);
}
}
재귀는 어떻습니까?
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");
}
}
그런 다음 호출 할 수 있습니다.
ReturnSize(size, string.Empty);
위에 게시 된 바와 같이 재귀는 로그의 도움으로 가장 선호되는 방법입니다.
다음 함수에는 3 개의 인수가 있습니다. 입력, 출력의 차원 제약 조건, 즉 세 번째 인수입니다.
int ByteReDim(unsigned long ival, int constraint, unsigned long *oval)
{
int base = 1 + (int) log10(ival);
(*oval) = ival;
if (base > constraint) {
(*oval) = (*oval) >> 10;
return(1 + ByteReDim((*oval), constraint, oval));
} else
return(0);
}
이제 12GB RAM을 여러 단위로 변환 해 보겠습니다.
int main(void)
{
unsigned long RAM;
int unit; // index of below symbols array
char symbol[5] = {'B', 'K', 'M', 'G', 'T'};
unit = ByteReDim(12884901888, 12, &RAM);
printf("%lu%c\n", RAM, symbol[unit]); // output is 12884901888B
unit = ByteReDim(12884901888, 9, &RAM);
printf("%lu%c\n", RAM, symbol[unit]); // output is 12582912K
unit = ByteReDim(12884901888, 6, &RAM);
printf("%lu%c\n", RAM, symbol[unit]); // output is 12288M
unit = ByteReDim(12884901888, 3, &RAM);
printf("%lu%c\n", RAM, symbol[unit]); // output is 12G
}
나는 이것을 Windows (이진 접두사)에 사용합니다.
static readonly string[] BinaryPrefix = { "bytes", "KB", "MB", "GB", "TB" }; // , "PB", "EB", "ZB", "YB"
string GetMemoryString(double bytes)
{
int counter = 0;
double value = bytes;
string text = "";
do
{
text = value.ToString("0.0") + " " + BinaryPrefix[counter];
value /= 1024;
counter++;
}
while (Math.Floor(value) > 0 && counter < BinaryPrefix.Length);
return text;
}
나는 이것을 거의 수정하지 않고 내 프로젝트의 UWP 데이터 바인딩 변환기에 통합했으며 다른 사람들에게도 유용 할 것이라고 생각했습니다.
코드는 다음과 같습니다.
using System;
using System.Text;
using Windows.UI.Xaml.Data;
namespace MyApp.Converters
{
public class ByteSizeConverter : IValueConverter
{
static readonly string[] sSizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
// The number of decimal places the formatter should include in the scaled output - default 1dp
public int DecimalPlaces { get; set; } = 1;
public object Convert(object value, Type targetType, object parameter, string language)
{
Int64 intVal = System.Convert.ToInt64(value);
return SizeSuffix(intVal);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
// TODO: Parse string into number and suffix
// Scale number by suffix multiplier to get bytes
throw new NotImplementedException();
}
string SizeSuffix(Int64 value)
{
if (this.DecimalPlaces < 0) { throw new ArgumentOutOfRangeException(String.Format("DecimalPlaces = {0}", this.DecimalPlaces)); }
if (value < 0) { return "-" + SizeSuffix(-value); }
if (value == 0) { return string.Format("{0:n" + this.DecimalPlaces + "} bytes", 0); }
// magnitude is 0 for bytes, 1 for KB, 2, for MB, etc.
int magnitude = (int)Math.Log(value, 1024);
// clip magnitude - only 8 values currently supported, this prevents out-of-bounds exception
magnitude = Math.Min(magnitude, 8);
// 1L << (magnitude * 10) == 2 ^ (10 * magnitude) [i.e. the number of bytes in the unit corresponding to magnitude]
decimal adjustedSize = (decimal)value / (1L << (magnitude * 10));
// make adjustment when the value is large enough that it would round up to 1000 or more
if (Math.Round(adjustedSize, this.DecimalPlaces) >= 1000)
{
magnitude += 1;
adjustedSize /= 1024;
}
return String.Format("{0:n" + this.DecimalPlaces + "} {1}", adjustedSize, sSizeSuffixes[magnitude]);
}
}
}
이를 사용하려면 UserControl 또는 페이지 XAML에 로컬 리소스를 추가합니다.
<UserControl.Resources>
<converters:ByteSizeConverter x:Key="ByteFormat" DecimalPlaces="3" />
</UserControl.Resources>
데이터 바인딩 템플릿 또는 데이터 바인딩 인스턴스에서 참조하십시오.
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Center"
Text="{x:Bind MyItem.FileSize_bytes, Mode=OneWay, Converter={StaticResource ByteFormat}}" />
그리고 안녕 프레스토. 마법이 일어난다.
https://github.com/logary/logary/blob/master/src/Logary/DataModel.fs#L832-L837
let scaleBytes (value : float) : float * string =
let log2 x = log x / log 2.
let prefixes = [| ""; "Ki"; "Mi"; "Gi"; "Ti"; "Pi" |] // note the capital K and the 'i'
let index = int (log2 value) / 10
1. / 2.**(float index * 10.),
sprintf "%s%s" prefixes.[index] (Units.symbol Bytes)
(면책 조항 : 링크에있는 코드까지도이 코드를 작성했습니다!)