.NETがこれを行うためのクリーンな方法を提供するかどうか疑問に思うだけです:
int64 x = 1000000;
string y = null;
if (x / 1024 == 0) {
y = x + " bytes";
}
else if (x / (1024 * 1024) == 0) {
y = string.Format("{0:n1} KB", x / 1024f);
}
等...
これを行うためのかなり簡潔な方法を次に示します。
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));
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 typoを修正しました...
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;
}
}
これも同じ方法の1つです(1073741824.0の数値は1024 * 1024 * 1024別名GB)。
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)
}
過剰なコメントがあるかもしれませんが、今後の訪問で同じ間違いを犯さないように、それらを残す傾向があります...
@ 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];
}
番号。
ただし、このように実装できます。
static double ConvertBytesToMegabytes(long bytes)
{
return (bytes / 1024f) / 1024f;
}
static double ConvertKilobytesToMegabytes(long kilobytes)
{
return kilobytes / 1024f;
}
また、チェックアウト バイト単位のファイルサイズをメガまたはギガバイトに正しく変換する方法?
ここでいくつかの答えを、うまく機能する2つの方法に組み合わせました。以下の2番目の方法は、バイト文字列(1.5.1 GBなど)をlong型の値としてバイト(1621350140など)に変換します。これが、バイトを文字列に変換してからバイトに戻すソリューションを探している他の人に役立つことを願っています。
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);
}
どうですか:
public void printMB(uint sizekB)
{
double sizeMB = (double) sizekB / 1024;
Console.WriteLine("Size is " + sizeMB.ToString("0.00") + "MB");
}
例えば。のように呼び出す
printMB(123456);
出力になります
"Size is 120,56 MB"
上記のように、再帰は対数の助けを借りて、お気に入りの方法です。
次の関数には3つの引数があります。入力、出力の次元制約、つまり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;
}
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)
私はJerKimballsのソリューションに行きました。しかし、これは全体として実際に論争の問題であることを追加/指摘したいと思います。私の研究では(他の理由で)次の情報を見つけました。
普通の人(私は彼らが存在すると聞いた)はギガバイトについて話すとき、彼らはメートル法で、元のバイト数から1000の3乗==ギガバイト数を指します。ただし、ウィキペディアでうまくまとめられているIEC/JEDEC標準もあり、1000のx乗の代わりに1024があります。物理ストレージデバイス(およびAmazonなど)は、メトリックとIECの差がますます大きくなることを意味します。したがって、たとえば1 TB == 1テラバイトメトリックは1000の4乗ですが、IECは正式には1 TiB、テビバイトの1024の4の累乗と同様の数値を表します。しかし、悲しいかな、非技術的なアプリケーション(私は聴衆によって行きます)では基準はメトリックであり、内部使用のための私自身のアプリでは現在、ドキュメントの違いを説明しています。しかし、表示目的のために、メトリック以外は提供していません。内部的にはアプリには関係ありませんが、バイトのみを保存し、表示のための計算を行います。
余談ですが、4.5のインカネーションであっても、.NetフレームワークAFAIK(およびその力に感謝することはよくありません)が内部的にライブラリにこれについて何も含まれていないことはやや不満です。ある種のオープンソースライブラリは、ある時点で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);