2009-02-04 7 views
12

Quiero obtener el tamaño de un archivo en disco en megabytes. Usando el operador -s me da el tamaño en bytes, pero voy a asumir que luego dividiendo este por un número mágico es una mala idea:¿Cómo obtengo el tamaño de un archivo en megabytes usando Perl?

my $size_in_mb = (-s $fh)/(1024 * 1024); 

¿Debo usar una variable de sólo lectura para definir 1024 o hay una forma programática de obtener la cantidad de bytes en un kilobyte?

EDIT: Se actualizó el cálculo incorrecto.

Respuesta

29

Si desea evitar los números mágicos, intente con el módulo CPAN Number::Bytes::Human.

use Number::Bytes::Human qw(format_bytes); 
my $size = format_bytes(-s $file); # 4.5M 
+1

Este módulo funciona muy bien, gracias. – cowgod

+0

acaba de descubrir que también puede analizar cadenas legibles en bytes. –

4

Bueno, no hay 1024 bytes en un meg, hay 1024 bytes en un K y 1024 K en un meg ...

Dicho esto, 1024 es un número de seguro "mágica" que nunca va a cambiar en cualquier sistema en el que pueda esperar que funcione su programa.

+0

una situación similar sería la conversión entre metros y kilómetros ... ¿Te sentirías mal por incluir el factor "mágico" de 1000? Esta es una conversión de unidad directa que NUNCA cambiará. – rmeador

+2

hablar con el marketing .. tienen una opinión diferente (mal en mi humilde opinión, pero bueno, tienen más dinero) – lexu

+0

Se ha actualizado la pregunta. Es temprano así que perdona mi confusión de kilobytes por megabytes. :) – cowgod

1

1) No quiere 1024. Eso le da kilobytes. Quiere 1024 * 1024 o 1048576.

2) ¿Por qué dividir por un número mágico sería una mala idea? No es como si el número de bytes en un megabyte cambiara alguna vez. No pienses demasiado las cosas.

0

No me malinterpreten, pero: creo que declarar 1024 como una Variable Mágica va demasiado lejos, es algo así como "$ ONE = 1; $ TWO = 2;" etc.

un kilobyte ha sido declarado falsamente como 1024 bytes desde hace más de 20 años, y tengo serias dudas de que los fabricantes de sistemas operativos serán siempre corregir ese error y el cambio a 1000.

Qué podría tener sentido, aunque es declarar cosas no evidentes, como "$ megabyte = 1024 * 1024", ya que es más fácil de leer que

1048576.
1

Dado que el operador -s devuelve el tamaño del archivo en bytes que probablemente debería estar haciendo algo así como

my $size_in_mb = (-s $fh)/(1024 * 1024); 

y use int() si necesita una figura redonda. No es que las dimensiones de KB o MB vayan a cambiar en el futuro próximo :)

4

Leería esto en una variable en lugar de usar un número mágico. Incluso si los números mágicos no van a cambiar, como el número de bytes en un megabyte, usar una constante bien llamada es una buena práctica porque hace que su código sea más legible. De inmediato es evidente para todos los demás cuál es tu intención.

6

Por supuesto, puede crear una función para calcular esto. Esa es una solución mejor que crear constantes en esta instancia.

sub size_in_mb { 
    my $size_in_bytes = shift; 
    return $size_in_bytes/(1024 * 1024); 
} 

No hay necesidad de constantes. Cambiar el 1024 a algún tipo de variable/constante no hará que este código sea más legible.

4

Esta es una pregunta antigua y ya ha sido respondida correctamente, pero por si su programa está restringido a los módulos centrales y no puede usar Number::Bytes::Human aquí tiene varias otras opciones que he recopilado con el tiempo.Los he mantenido también porque cada uno de los usos de un enfoque Perl diferente y es un buen ejemplo para TIMTOWTDI:

  • ejemplo 1: utiliza el estado para evitar reinicializar la variable cada vez (antes de Perl 5.16 es necesario utilizar estado de la función o Perl -E)

http://kba49.wordpress.com/2013/02/17/format-file-sizes-human-readable-in-perl/

sub formatSize { 
     my $size = shift; 
     my $exp = 0; 

     state $units = [qw(B KB MB GB TB PB)]; 

     for (@$units) { 
      last if $size < 1024; 
      $size /= 1024; 
      $exp++; 
     } 

     return wantarray ? ($size, $units->[$exp]) : sprintf("%.2f %s", $size, $units->[$exp]); 
    } 
  • ejemplo 2: el uso de tipo mapa

.

sub scaledbytes { 

    # http://www.perlmonks.org/?node_id=378580 
    (sort { length $a <=> length $b 
      } map { sprintf '%.3g%s', $_[0]/1024**$_->[1], $_->[0] 
       }[" bytes"=>0] 
       ,[KB=>1] 
       ,[MB=>2] 
       ,[GB=>3] 
       ,[TB=>4] 
       ,[PB=>5] 
       ,[EB=>6] 
    )[0] 
    } 
  • ejemplo 3: Tome ventaja del hecho de que 1 Gb = 1,024 Mb, 1 Mb = 1,024 Kb y 1024 = 2 ** 10:

.

# http://www.perlmonks.org/?node_id=378544 
my $kb = 1024 * 1024; # set to 1 Gb 

my $mb = $kb >> 10; 
my $gb = $mb >> 10; 

print "$kb kb = $mb mb = $gb gb\n"; 
__END__ 
1048576 kb = 1024 mb = 1 gb 
  • ejemplo 4: uso de ++$n and ... until .. para obtener un índice de la matriz de

.

# http://www.perlmonks.org/?node_id=378542 
#! perl -slw 
use strict; 

sub scaleIt { 
    my($size, $n) =(shift, 0); 
    ++$n and $size /= 1024 until $size < 1024; 
    return sprintf "%.2f %s", 
      $size, (qw[ bytes KB MB GB ])[ $n ]; 
} 

my $size = -s $ARGV[ 0 ]; 

print "$ARGV[ 0 ]: ", scaleIt $size; 

Incluso si usted no puede usar el Número de Bytes :: :: humana, echar un vistazo al código fuente para ver todas las cosas que usted necesita para tener en cuenta.

Cuestiones relacionadas