在進行程式設計的時候,有時會需要進行檔案大小或是資料大小的輸入與輸出,甚至會需要對其做一些運算。做這件事有什麼困難的嗎?我們應該都知道,8個位元是1個位元組(Byte),1000個位元組是1KB,而1000KB是1MB。在設計程式的時候,如果要將一個以位元組為單位的值,選擇適當的單位來輸出(例如1200位元組要輸出成1.20MB、5555555位元組要輸出成5.56MB)的話,就必須要多撰寫幾行程式來完成。如果是資料輸入的時候,假設使用者輸入的是「3.6MB」,程式也許需要多撰寫幾行程式,將其轉為「3600000」來儲存,表示為「3600000個位元組」;輸入「25KB」,就要轉成「25000」。這些雖然都是簡單的事情,且所需要的程式碼量也不大,但就是由於簡單又常用,每次都要在不同專案寫一樣的程式去處理就會覺得很煩躁,所以乾脆將其發展為一個獨立的套件,就能不斷地重複使用了。



Byte Unit

「Byte Unit」是筆者開發的套件,實現了位元組(B)、KB、KiB、MB、MiB、GB、GiB、TB、TiB、PB、PiB的大小單位換算。

KB、MB、GB、TB、PB等都是基於1000的單位,而KiB、MiB、GiB、TiB、PiB等則是基於1024的單位。

1KB  = 1000
1KiB = 1024
1MB  = 1000000
1MiB = 1048576
1GB  = 1000000000
1GiB = 1073741824
1TP  = 1000000000000
1TiB = 1099511627776
1PB  = 1000000000000000
1PiB = 1125899906842624

另外,儲存位元組的數值型別是採用u128,而非u64或u32,因此不用害怕會溢位。

Crates.io

https://crates.io/crates/byte-unit

Cargo.toml

byte-unit = "*"

使用方法

使用「use」關鍵字來將「byte-unit」這個crate底下的「Byte」結構體給引用到當前的程式範圍下。「Byte」結構體可用來儲存與表示一個位元組的大小。

使用「Byte」結構體的「from_unit」關聯函數,可以透過參數傳入要儲存的位元組大小,來建立出「Byte」結構實體。

extern crate byte_unit;

use byte_unit::{Byte, ByteUnit};

let result = Byte::from_bytes(1500000u128);

assert_eq!(result.get_bytes(), 1500000u128);

使用「Byte」結構體的「from_unit」關聯函數,可以透過參數傳入要儲存的數值和單位,來建立出「Byte」結構實體。由於最終會將數值以位元組來儲存,因此在轉換的過程中可以會損失一些精確度。傳入的數值之型別為f64。

extern crate byte_unit;

use byte_unit::{Byte, ByteUnit};

let result = Byte::from_unit(1500f64, ByteUnit::KB).unwrap();

assert_eq!(result.get_bytes(), 1500000u128);

使用「Byte」結構體的「from_string」關聯函數,可以透過參數以字串的形式傳入要儲存的數值和單位,來建立出「Byte」結構實體。

extern crate byte_unit;

use byte_unit::{Byte, ByteUnit};

let result = Byte::from_string("123KiB").unwrap();

assert_eq!(result, Byte::from_unit(123f64, ByteUnit::KiB).unwrap());
extern crate byte_unit;

use byte_unit::{Byte, ByteUnit};

let result = Byte::from_string("50.84 MB").unwrap();

assert_eq!(result, Byte::from_unit(50.84f64, ByteUnit::MB).unwrap());

有了「Byte」結構實體之後,除了能夠使用「get_bytes」方法取得其位元組數值之外,還可以使用「get_adjusted_unit」方法,來建立出單位並不一定是位元組的「AdjustedByte」結構實體。透過「get_adjusted_unit」方法的參數傳入「ByteUnit」列舉的變體,可以指定「get_adjusted_unit」方法所回傳的「AdjustedByte」結構實體要使用哪個單位。

extern crate byte_unit;

use byte_unit::{Byte, ByteUnit};

let byte = Byte::from_string("123KiB").unwrap();

let adjusted_byte = byte.get_adjusted_unit(ByteUnit::KB);

assert_eq!(adjusted_byte.to_string(), "125.95 KB");

如果懶得自己指定單位,也可以使用「Byte」結構實體的「get_appropriate_unit」方法,來建立出已自動選擇好適當單位的「AdjustedByte」結構實體,還可以決定要使用以1000還是以1024為基礎的單位。

extern crate byte_unit;

use byte_unit::Byte;

let byte = Byte::from_string("123KiB").unwrap();

let adjusted_byte = byte.get_appropriate_unit(false);

assert_eq!(adjusted_byte.to_string(), "125.95 KB");
extern crate byte_unit;

use byte_unit::Byte;

let byte = Byte::from_string("50.84 MB").unwrap();

let adjusted_byte = byte.get_appropriate_unit(true);

assert_eq!(adjusted_byte.to_string(), "48.48 MiB");

「AdjustedByte」結構實體可以使用「to_string」方法來將資料大小的數值自動轉成字串。字串中數值的部份,小數點會固定取到後兩位。如果想要使用別種格式化字串的方式,可以使用「get_value」方法和「get_unit」方法來取得原始的數值和單位來作應用。

巨集的使用

Byte Unit還提供了幾個巨集,可以方便且有效率地將任意單位的大小轉換成位元組。

巨集的命名方式如下:

n_<單位>_bytes

例如:

n_kb_bytes

n_gib_bytes

用法如下:

#[macro_use]
extern crate byte_unit;

let result = n_kb_bytes!(4);

assert_eq!(result, 4000u128);

如果數值是浮點數的話,可以在第二個參數傳入它的型別來保留小數點後的資料,如下:

#[macro_use]
extern crate byte_unit;

let result = n_kb_bytes!(2.5, f64);

assert_eq!(result, 2500u128);