2009-02-04 32 views
12

Tôi muốn lấy kích thước của một tệp trên đĩa theo megabyte. Sử dụng các nhà điều hành -s mang lại cho tôi kích thước tính bằng byte, nhưng tôi sẽ cho rằng sau đó chia này bằng một con số kỳ diệu là một ý tưởng tồi:Làm cách nào để nhận được kích thước tệp bằng megabyte bằng Perl?

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

nên tôi chỉ sử dụng một chỉ đọc biến để xác định năm 1024 hoặc là có một cách lập trình để có được số lượng byte trong một kilobyte?

EDIT: Cập nhật phép tính không chính xác.

Trả lời

29

Nếu bạn muốn tránh các số ma thuật, hãy thử mô-đun CPAN Number::Bytes::Human.

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

Mô-đun này hoạt động tốt, cảm ơn. – cowgod

+0

vừa phát hiện ra nó cũng có thể phân tích cú pháp chuỗi có thể đọc được của con người trở lại thành byte! –

4

Vâng, không có 1024 byte trong một meg, có 1024 byte trong một K, và 1024 K trong một meg ...

Điều đó nói rằng, 1024 là một an toàn "ma thuật" con số đó sẽ không bao giờ thay đổi trong bất kỳ hệ thống nào bạn có thể mong đợi chương trình của bạn hoạt động.

+0

tình huống tương tự sẽ chuyển đổi giữa mét và ki lô mét ... bạn có cảm thấy xấu về việc bao gồm yếu tố "ma thuật" 1000 không? Đây là một chuyển đổi đơn vị thẳng sẽ KHÔNG BAO GIỜ thay đổi. – rmeador

+2

nói chuyện với tiếp thị .. họ có một ý kiến ​​khác (sai IMHO, nhưng hey, họ có nhiều tiền hơn) – lexu

+0

Cập nhật câu hỏi. Đó là sớm để tha thứ cho sai lầm của tôi về kilobyte cho megabyte. :) – cowgod

1

1) Bạn không muốn 1024. Điều đó mang lại cho bạn số kilobyte. Bạn muốn 1024 * 1024 hoặc 1048576.

2) Tại sao việc chia số ma thuật lại là một ý tưởng tồi? Nó không giống như số byte trong một megabyte sẽ bao giờ thay đổi. Đừng suy nghĩ quá nhiều.

0

Đừng hiểu lầm tôi, nhưng: Tôi nghĩ rằng việc khai báo 1024 là một biến Magic biến mất một chút quá xa, đó là một chút như "$ ONE = 1; $ TWO = 2;" vv

Một Kilobyte đã được khai báo sai như 1024 Bytes kể từ hơn 20 năm, và tôi nghiêm túc nghi ngờ rằng các nhà sản xuất hệ điều hành sẽ bao giờ sửa lỗi và thay đổi nó để 1000.

Điều gì có thể làm cho tinh thần mặc dù là khai báo thứ không rõ ràng, như "$ megabyte = 1024 * 1024" vì đó là dễ đọc hơn so 1048576.

1

kể từ khi các nhà điều hành -s trả về kích thước tập tin theo byte có lẽ bạn nên làm một cái gì đó giống như

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

và sử dụng int() nếu bạn cần một hình tròn. Nó không giống như kích thước của KB hoặc MB sẽ thay đổi bất cứ lúc nào trong tương lai gần :)

4

Tôi sẽ đọc điều này thành một biến thay vì sử dụng số ma thuật. Ngay cả khi các con số ma thuật sẽ không thay đổi, như số byte trong megabyte, thì sử dụng hằng số được đặt tên tốt là một thực hành tốt vì nó làm cho mã của bạn dễ đọc hơn. Nó làm cho nó rõ ràng ngay lập tức cho tất cả mọi người khác ý định của bạn là gì.

6

Bạn có thể tạo một hàm để tính toán điều này. Đó là một giải pháp tốt hơn so với việc tạo các hằng số trong trường hợp này.

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

Không cần hằng số. Thay đổi 1024 thành một số loại biến/hằng số sẽ không làm cho mã này dễ đọc hơn.

4

Đây là câu hỏi cũ và đã được trả lời đúng, nhưng chỉ trong trường hợp chương trình của bạn bị ràng buộc với các mô-đun cốt lõi và bạn không thể sử dụng Number::Bytes::Human tại đây bạn có một số tùy chọn khác mà tôi đã thu thập theo thời gian.Tôi đã giữ họ cũng bởi vì mỗi người sử dụng một cách tiếp cận Perl khác nhau và là một ví dụ tốt đẹp cho TIMTOWTDI:

  • dụ 1: sử dụng nhà nước để tránh reinitialize biến mỗi lần (trước perl 5,16 bạn cần phải sử dụng nhà nước tính năng hay 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]); 
    } 
  • dụ 2: sử dụng loại bản đồ

.

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] 
    } 
  • dụ 3: Tận dụng lợi thế của thực tế là 1 Gb = 1024 Mb, 1 Mb = 1024 Kb và 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 
  • dụ 4: sử dụng ++$n and ... until .. để có được một chỉ số cho mảng

.

# 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; 

Thậm chí nếu bạn không thể sử dụng Số :: Bytes :: Con người, hãy xem mã nguồn để xem tất cả những thứ bạn cần biết.

Các vấn đề liên quan