Convert "1.5 TB", "500 MB" to a file size unit

I want to allow the user to enter the file size using any of the standard suffixes (e.g. TB, MB, GB)

I would like to get the value so that I can compare them with the size of the folder.

The idea is to have a program that will warn if the folder exceeds a certain size, the size of which is determined by the line entered by the user.

Is there anything built into the .net framework that allows me to parse strings like 1.5TB , 400GB , 1.9GB and 0.5KB ?

+6
source share
3 answers

This is a good candidate for a simple Interpreter .

Code like this is a simple start, you will need to handle perhaps more cases and take into account differences in the package (e.g. Gb vs Gb ).

You start by defining the context and expression:

 public class FileSizeContext { private string input; private long output; public FileSizeContext(string input) { this.Input = input; } public string Input { get; set; } public long Output { get; set; } } public abstract class FileSizeExpression { public abstract void Interpret(FileSizeContext value); } 

Then you define your terminal expression and all options:

 public abstract class TerminalFileSizeExpression : FileSizeExpression { public override void Interpret(FileSizeContext value) { if(value.Input.EndsWith(this.ThisPattern())) { double amount = double.Parse(value.Input.Replace(this.ThisPattern(),String.Empty)); var fileSize = (long)(amount*1024); value.Input = String.Format("{0}{1}",fileSize,this.NextPattern()); value.Output = fileSize; } } protected abstract string ThisPattern(); protected abstract string NextPattern(); } public class KbFileSizeExpression : TerminalFileSizeExpression { protected override string ThisPattern(){return "KB";} protected override string NextPattern() { return "bytes"; } } public class MbFileSizeExpression : TerminalFileSizeExpression { protected override string ThisPattern() { return "MB"; } protected override string NextPattern() { return "KB"; } } public class GbFileSizeExpression : TerminalFileSizeExpression { protected override string ThisPattern() { return "GB"; } protected override string NextPattern() { return "MB"; } } public class TbFileSizeExpression : TerminalFileSizeExpression { protected override string ThisPattern() { return "TB"; } protected override string NextPattern() { return "GB"; } } 

Then you add a nonterminal expression (this does the bulk of the work):

 public class FileSizeParser : FileSizeExpression { private List<FileSizeExpression> expressionTree = new List<FileSizeExpression>() { new TbFileSizeExpression(), new GbFileSizeExpression(), new MbFileSizeExpression(), new KbFileSizeExpression() }; public override void Interpret(FileSizeContext value) { foreach (FileSizeExpression exp in expressionTree) { exp.Interpret(value); } } } 

Finally, here is what the client code is:

 var ctx = new FileSizeContext("10Mb"); var parser = new FileSizeParser(); parser.Interpret(ctx); Console.WriteLine("{0} bytes", ctx.Output); // 10485760 bytes 

Real-time example: http://rextester.com/rundotnet?code=WMGOQ13650

edits. Changed for MB from Mb (one officially MegaByte another - MegaBit). The int value has been changed to accommodate large sizes.

+8
source

Short answer: no, there is no built-in method.

Long answer: use my converter.

 public class FileSizeConverter { private static System.Globalization.NumberFormatInfo numberFormat; private static Dictionary<string, long> knownUnits; static FileSizeConverter() { knownUnits = new Dictionary<string, long> { { "", 1L }, // no unit is same as unit B(yte) { "B", 1L }, { "KB", 1024L }, { "MB", 1024L * 1024L}, { "GB", 1024L * 1024L * 1024L}, { "TB", 1024L * 1024L * 1024L * 1024L} // fill rest as needed }; // since I live in a locale where "," is the decimal separator I will enforce US number format numberFormat = new System.Globalization.CultureInfo("en-US").NumberFormat; } public long Parse(string value) { // ignore spaces around the actual value value = value.Trim(); string unit = ExtractUnit(value); string sizeAsString = value.Substring(0, value.Length - unit.Length).Trim(); // trim spaces long multiplicator = MultiplicatorForUnit(unit); decimal size; if (!decimal.TryParse(sizeAsString, System.Globalization.NumberStyles.Number, numberFormat, out size)) throw new ArgumentException("illegal number", "value"); return (long)(multiplicator * size); } private bool IsDigit(char value) { // we don't want to use char.IsDigit since it would accept esoterical unicode digits if (value < '0') return false; if (value > '9') return false; return true; } private string ExtractUnit(string sizeWithUnit) { // start right, end at the first digit int lastChar = sizeWithUnit.Length-1; int unitLength = 0; while (unitLength <= lastChar && sizeWithUnit[lastChar - unitLength] != ' ' // stop when a space && !IsDigit(sizeWithUnit[lastChar - unitLength])) // or digit is found { unitLength++; } return sizeWithUnit.Substring(sizeWithUnit.Length - unitLength).ToUpperInvariant(); } private long MultiplicatorForUnit(string unit) { unit = unit.ToUpperInvariant(); if (!knownUnits.ContainsKey(unit)) throw new ArgumentException("illegal or unknown unit", "unit"); return knownUnits[unit]; } } 

EDIT : here's a live demo: http://rextester.com/rundotnet?code=BQYCB2587 (thanks @Jamiec for the link, very convenient for running C # source online)

+4
source

I could not find such functionality in the .NET Framework with a quick Google search, so I assume that it is possible to implement it.

I think that splitting a string into numeric values ​​and a period (or a comma, I think, international) as the first part and extracting KB / MB / etc as the second part and analyzing each part manually will be a way.

+3
source

Source: https://habr.com/ru/post/896780/


All Articles