C#. Unidades de capacidad

No será la primera vez que hemos creado algún sistema de visualización de archivos y, casi siempre solemos poner lo mismo, es decir, un grid en el que aparecen datos como Nombre, Extensión, Tamaño… Hoy me he fijado en el tamaño.

La magnífica clase System.IO.FileInfo nos proporciona casi todos los elementos a los que solemos hacer referencia cuando trabajamos con algún que otro archivo. Las propiedades Name, FullName, Extension y Length quizás sean los elementos más socorridos a la hora de mostrar algún que otro grid con los datos. El “problema” que le veo es que la longitud del fichero siempre nos lo está devolviendo en una misma medida, en bytes.

grid_bytes

 

¿Qué pasa si no quiero que se muestre así?. En un caso particular que me lleva ahora, al tratarse de ficheros bastante grandes, he preferido mostrar las unidades bastante abreviadas, del tipo 20,23 Mb o 34,21 Kb. Algo así como en el siguiente ejemplo:

grid_medidas

 

Bueno, supongo que el ejemplo queda claro, aunque también supongo que habrá alguien que deje el comentario refiriéndose que es más cómodo para ordenar y para hacerse una idea en una misma medida que en varias. ¡Vale!,.es el riesgo de publicar algo en Internet pero… para gustos, colores.

Vamos al grano, es decir, a crear una clase en C# que convierta una determinada cantidad de bytes en cualquier otra más abreviada. Al principio de esta labor, rememorando las clases de fundamentos de programación estuve tentado de hacer algún tipo de algoritmo de búsqueda para poder encontrar cuál era el número por el que podíamos dividir los bytes para que no fuesen 0 que, al fin y al cabo, es la única dificultad que estriba este módulo. Al final veo que también las clases de análisis en las que me intentaban explicar la funcionalidad de los logaritmos dejaron algún tipo de mella en mí.

Manos a la obra.

Necesito crear algún tipo de método en el que, pasándole un número de bytes como parámetro, nos devuelva una unidad abreviada. Así, si pasamos, por ejemplo, 2048 Bytes, el resultado que me devolverá será 2 Kb. En principio, la idea es crear un método estático del tipo.

   1: public static string GetFileSize(long numBytes)
   2: {
   3:     // TODO : Pendiente de implementar 
   4: }

Aunque, al empezar a crear el método, apercibo que será mucho mejor poder especificar desde la capa de presentación el formato. En este apartado no sé si se hace así o hubiese sido mejor echar mano de la UICulture, pero por comodidad he optado por hacer una pequeña “trampilla”. En este caso, la bendita sobrecarga ofrece la posibilidad de especificar el formato siguiendo las normas del formato compuesto, siendo {0} la cantidad y {1} la unidad de medida.

 

   1: public static string GetFileSize(long numBytes)
   2: {
   3:     return GetFileSize(numBytes, "{0:N0} {1}");
   4: }
   5:  
   6: public static string GetFileSize(long numBytes, string format)
   7: {
   8:     // TODO : Pendiente de implementar
   9: }

 

Una vez establecido el inicio y resuelto el problema de cómo localizar la unidad de un modo correcto, sólo nos queda el desarrollo del resto de la clase:

   1: using System;
   2:  
   3:  
   4:  
   5: namespace JnSoftware.Utiles
   6: {
   7:  
   8:     /// <summary>
   9:     /// Servicios de utilidad general de trabajo con ficheros
  10:     /// </summary>
  11:     public class Ficheros
  12:     {
  13:  
  14:         /// <summary>
  15:         /// Posibles capacidades de un archivo
  16:         /// </summary>
  17:         public enum CapacidadEnum
  18:         {
  19:             /// <summary>
  20:             /// Byte
  21:             /// </summary>
  22:             Byte = 0,
  23:             /// <summary>
  24:             /// Kilobyte
  25:             /// </summary>
  26:             Kb = 1,
  27:             /// <summary>
  28:             /// Megabyte
  29:             /// </summary>
  30:             Mb = 2,
  31:             /// <summary>
  32:             /// Gigabyte
  33:             /// </summary>
  34:             Gb = 3,
  35:             /// <summary>
  36:             /// Terabyte
  37:             /// </summary>
  38:             Tb = 4,
  39:             /// <summary>
  40:             /// Petabyte
  41:             /// </summary>
  42:             Pt = 5,
  43:             /// <summary>
  44:             /// Exabyte
  45:             /// </summary>
  46:             Ex = 6,
  47:             /// <summary>
  48:             /// Zetabyte
  49:             /// </summary>
  50:             Zb = 7
  51:         }
  52:  
  53:         private const long baseExp = 1024; // 2 ^10
  54:  
  55:         /// <summary>
  56:         /// Obtiene el valor de la medida en la que nos encontraremos
  57:         /// con valores diferentes de 0.
  58:         /// </summary>
  59:         /// <param name="numBytes">Bytes del fichero</param>
  60:         private int getPotencia(long numBytes)
  61:         {
  62:             return (int)Math.Log(numBytes, baseExp);
  63:         }
  64:  
  65:  
  66:         /// <summary>
  67:         /// Obtiene la unidad de capacidad
  68:         /// </summary>
  69:         /// <param name="potencia">Valor de la medida en la que nos
  70:         /// encontramos con valores diferentes de 0</param>
  71:         private string getUnidadCapacidad(int potencia)
  72:         {
  73:             return Enum.GetName(typeof(CapacidadEnum), potencia);
  74:         }
  75:  
  76:  
  77:  
  78:         private string getSizeAndUnity(long numBytes, string formatoNumerico)
  79:         {
  80:             int pot = getPotencia(numBytes);
  81:             double valor;
  82:             if (pot != 0)
  83:                 valor = numBytes / (Math.Pow(baseExp, pot));
  84:             else
  85:                 valor = numBytes;
  86:  
  87:             string unidad = getUnidadCapacidad(pot);
  88:             return string.Format(formatoNumerico, valor, unidad);
  89:         }
  90:  
  91:  
  92:  
  93:         /// <summary>
  94:         /// Estandariza el tamaño pasado como parámetro
  95:         /// en unidad de capacidad informática
  96:         /// </summary>
  97:         /// <param name="numBytes">Bytes del fichero</param>
  98:         /// <returns>
  99:         /// Cadena de texto en formato "{0:N0} {1}", siendo el 
 100:         /// primer parámetro el número de bytes y el segundo parámetro
 101:         /// la unidad de capacidad
 102:         /// </returns>
 103:         public static string GetFileSize(long numBytes)
 104:         {
 105:             return GetFileSize(numBytes, "{0:N0} {1}");
 106:         }
 107:  
 108:  
 109:  
 110:         /// <summary>
 111:         /// Estandariza el tamaño pasado como parámetro
 112:         /// en unidad de capacidad informática
 113:         /// </summary>
 114:         /// <param name="numBytes">Bytes del fichero</param>
 115:         /// <param name="format">Cadena de formato compuesto.
 116:         ///     {0} = Cantidad numérica
 117:         ///     {1} = Unidad de medida
 118:         /// </param>
 119:         /// <returns>
 120:         /// Cadena de texto en formato "{0:N0} {1}", siendo el 
 121:         /// primer parámetro el número de bytes y el segundo parámetro
 122:         /// la unidad de capacidad</returns>
 123:         public static string GetFileSize(long numBytes, string format)
 124:         {
 125:             Ficheros f = new Ficheros();
 126:             return f.getSizeAndUnity(numBytes, format);
 127:         }
 128:  
 129:  
 130:  
 131:     }
 132: }

Observaciones

Imagino que alguien me comentará que me he dejado el YottaByte en la enumeración. ¡Pues vale!, Pasando de los Mb, el resto lo puse más porque me hacía gracia que por la utilidad. Hasta el momento no suelo estar habituado a trabajar con ficheros que superen los Tb.

También me anduve mirando otro punto un poco delicado, referente a los prefijos binarios, sobretodo, por las diferencias existentes entre las medidas de discos y las estándares y, al final he optado por seguir la unidad estándar. Al fin y al cabo, la necesidad inicial era la de trabajar con ficheros almacenados en un servidor Web… No sé si realmente notaré mucho las diferencias hablando de mebis o megas…

3 thoughts on “C#. Unidades de capacidad

Responder a jvelasco Cancelar respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *