add new SI prefixes (#28)
[storage-units.git] / README.md
blob662f0e8a97c2b3f9bf3508602b59f91142c15f9b
1 <!--
2 SPDX-FileCopyrightText: The Storage-Units Authors
3 SPDX-License-Identifier: 0BSD
4  -->
6 # Storage-Units
8 Storage units according to ISO IEC 80000-13:2008 implemented in Java.
10 ## Features
12 * Immutable, type- and thread-safe object model for storage units
13 * Convenience factories to create units
14 * Basic arithmetic operators
15 * Comparisons and equality checks between units
16 * Lossless conversion between all units
17 * Human-readable text format, including custom formats
18 * Compatible with any `java.lang.Number`
19 * Custom serializers for Jackson, MongoDB, EclipseLink, and others
21 ### Available Units
23 | Name     | Symbol | Exponential          | Absolute                                       |
24 |----------|--------|----------------------|------------------------------------------------|
25 | Byte     | B      | 2<sup>0</sup> Byte   | 1 Byte                                         |
26 | Kibibyte | KiB    | 2<sup>10</sup> Byte  | 1 024 Byte                                     |
27 | Mebibyte | MiB    | 2<sup>20</sup> Byte  | 1 048 576 Byte                                 |
28 | Gibibyte | GiB    | 2<sup>30</sup> Byte  | 1 073 741 824 Byte                             |
29 | Tebibyte | TiB    | 2<sup>40</sup> Byte  | 1 099 511 627 776 Byte                         |
30 | Pebibyte | PiB    | 2<sup>50</sup> Byte  | 1 125 899 906 842 624 Byte                     |
31 | Exbibyte | EiB    | 2<sup>60</sup> Byte  | 1 152 921 504 606 846 976 Byte                 |
32 | Zebibyte | ZiB    | 2<sup>70</sup> Byte  | 1 180 591 620 717 411 303 424 Byte             |
33 | Yobibyte | YiB    | 2<sup>80</sup> Byte  | 1 208 925 819 614 629 174 706 176 Byte         |
34 | Robibyte | RiB    | 2<sup>90</sup> Byte  | 1 237 940 039 285 380 274 899 124 224 Byte     |
35 | Qubibyte | QiB    | 2<sup>100</sup> Byte | 1 267 650 600 228 229 401 496 703 205 376 Byte |
37 | Name       | Symbol | Exponential          | Absolute                                       |
38 |------------|--------|----------------------|------------------------------------------------|
39 | Byte       | B      | 10<sup>0</sup> Byte  | 1 Byte                                         |
40 | Kilobyte   | KB     | 10<sup>3</sup> Byte  | 1 000 Byte                                     |
41 | Megabyte   | MB     | 10<sup>6</sup> Byte  | 1 000 000 Byte                                 |
42 | Gigabyte   | GB     | 10<sup>9</sup> Byte  | 1 000 000 000 Byte                             |
43 | Terabyte   | TB     | 10<sup>12</sup> Byte | 1 000 000 000 000 Byte                         |
44 | Petabyte   | PB     | 10<sup>15</sup> Byte | 1 000 000 000 000 000 Byte                     |
45 | Exabyte    | EB     | 10<sup>18</sup> Byte | 1 000 000 000 000 000 000 Byte                 |
46 | Zettabyte  | ZB     | 10<sup>21</sup> Byte | 1 000 000 000 000 000 000 000 Byte             |
47 | Yottabyte  | YB     | 10<sup>24</sup> Byte | 1 000 000 000 000 000 000 000 000 Byte         |
48 | Ronnabyte  | RB     | 10<sup>27</sup> Byte | 1 000 000 000 000 000 000 000 000 000 Byte     |
49 | Quettabyte | QB     | 10<sup>30</sup> Byte | 1 000 000 000 000 000 000 000 000 000 000 Byte |
51 ## Usage
53 ### Factories
55 Each unit implements a Byte-based static factory method (`valueOf(BigInteger)` or `valueOf(long)`) that can be used to represent a given number of bytes in a specific unit. Note that `Long.MAX_VALUE == 8 Exabyte`, thus use `BigInteger` if you want to work with anything bigger than a eight Exabyte. When in doubt, always use `BigInteger`.
57 ```java
58 // 'long' based
59 Kilobyte unit = Kilobyte.valueOf(500)                           // 500 Byte or "0.50 kB"
60 Kibibyte unit = Kibibyte.valueOf(512)                           // 512 Byte or "0.50 KiB"
62 Megabyte unit = Megabyte.valueOf(1_000_000)                     // 1 000 000 Byte or "1.00 MB"
63 Mebibyte unit = Mebibyte.valueOf(1_048_576)                     // 1 048 576 Byte or "1.00 MiB"
65 // 'BigInteger' based
66 Kilobyte unit = Kilobyte.valueOf(BigInteger.valueOf(500))       // 500 Byte or "0.50 kB"
67 Kibibyte unit = Kibibyte.valueOf(BigInteger.valueOf(512))       // 512 Byte or "0.50 KiB"
69 Megabyte unit = Megabyte.valueOf(BigInteger.valueOf(1000000))   // 1 000 000 Byte or "1.00 MB"
70 Mebibyte unit = Mebibyte.valueOf(BigInteger.valueOf(1_048_576)) // 1 048 576 Byte or "1.00 MB"
71 ```
73 The `StorageUnits` class offers three factory methods that automatically pick the best-matching unit for a given number of bytes.
75 #### Binary Units
77 ```java
78 // 'long' based
79 StorageUnit<?> unit = StorageUnits.binaryValueOf(256)                         // Kibibyte (0.25 KiB)
80 StorageUnit<?> unit = StorageUnits.binaryValueOf(1048576)                     // Mebibyte (1.00 MiB)
82 // 'BigInteger' based
83 StorageUnit<?> unit = StorageUnits.binaryValueOf(BigInteger.valueOf(256))     // Kibibyte (0.25 MiB)
84 StorageUnit<?> unit = StorageUnits.binaryValueOf(BigInteger.valueOf(1048576)) // Mebibyte (1.00 MiB)
85 ```
87 #### Decimal Units
89 ```java
90 // 'long' based
91 StorageUnit<?> unit = StorageUnits.decimalValueOf(120000)                      // Kilobyte (120.00 kB)
92 StorageUnit<?> unit = StorageUnits.decimalValueOf(1000000)                     // Megabyte (1.00 MB)
94 // 'BigInteger' based
95 StorageUnit<?> unit = StorageUnits.decimalValueOf(BigInteger.valueOf(120000))  // Kilobyte (120.00 kB)
96 StorageUnit<?> unit = StorageUnits.decimalValueOf(BigInteger.valueOf(1000000)) // Megabyte (1.00 MB)
97 ```
99 Additionally high-level factory methods are also available in the `StorageUnits` class.
101 ```java
102 import static wtf.metio.storageunits.model.StorageUnits.*;
104 Kibibyte unit = kibibyte(1)   // 1 024 Byte
105 Mebibyte unit = mebibyte(1)   // 1 048 576 Byte
106 Gibibyte unit = gibibyte(1)   // 1 073 741 824 Byte
107 Tebibyte unit = tebibyte(1)   // 1 099 511 627 776 Byte
108 Pebibyte unit = pebibyte(1)   // 1 125 899 906 842 624 Byte
109 Exbibyte unit = exbibyte(1)   // 1 152 921 504 606 846 976 Byte
110 Zebibyte unit = zebibyte(1)   // 1 180 591 620 717 411 303 424 Byte
111 Yobibyte unit = yobibyte(1)   // 1 208 925 819 614 629 174 706 176 Byte
112 Robibyte unit = robibyte(1)   // 1 237 940 039 285 380 274 899 124 224 Byte
113 Qubibyte unit = qubibyte(1)   // 1 267 650 600 228 229 401 496 703 205 376 Byte
115 Kilobyte unit = kilobyte(1)     // 1 000 Byte
116 Megabyte unit = megabyte(1)     // 1 000 000 Byte
117 Gigabyte unit = gigabyte(1)     // 1 000 000 000 Byte
118 Terabyte unit = terabyte(1)     // 1 000 000 000 000 Byte
119 Petabyte unit = petabyte(1)     // 1 000 000 000 000 000 Byte
120 Exabyte unit = exabyte(1)       // 1 000 000 000 000 000 000 Byte
121 Zettabyte unit = zettabyte(1)   // 1 000 000 000 000 000 000 000 Byte
122 Yottabyte unit = yottabyte(1)   // 1 000 000 000 000 000 000 000 000 Byte
123 Ronnabyte unit = ronnabyte(1)   // 1 000 000 000 000 000 000 000 000 000 Byte
124 Quettabyte unit = quettabyte(1) // 1 000 000 000 000 000 000 000 000 000 000 Byte
127 ### Add, Subtract, Multiply, Divide
129 Each unit implements the basic four math operations. All operations retain their original type, e.g. `[Kilobyte] + [Megabyte] = [Kilobyte]`
131 ```java
132 import static wtf.metio.storageunits.model.StorageUnits.*;
134 kilobyte(4).add(kilobyte(8))        // 4 Kilobyte + 8 Kilobyte = 12 Kilobyte = 12 000 Byte
135 kibibyte(1).add(1024)               // 1 Kibibyte + 1 024 Byte = 2 Kibibyte = 2 048 Byte
136 kibibyte(1).subtract(24)            // 1 024 Byte - 24 Byte = 1 000 Byte
137 megabyte(5).subtract(kilobyte(500)) // 5 Megabyte - 500 Kilobyte = 4.5 Megabyte = 4 500 Kilobyte = 4 500 000 Byte
138 gigabyte(1).multiply(5)             // 1 Gigabyte times 5 = 5 Gigabyte
139 terabyte(1).divide(5)               // 1 Terabyte divided by 5 = 0.2 Terabyte = 200 Gigabyte
142 ### Comparison & Equality
144 Each unit is comparable to each other unit.
146 ```java
147 import static wtf.metio.storageunits.model.StorageUnits.*;
149 kibibyte(1024).compareTo(mebibyte(1)) == 0 // true
150 kibibyte(1000).compareTo(mebibyte(1)) == 0 // false
151 petabyte(3).compareTo(terabyte(3000)) == 0 // true
153 megabyte(1000).equals(gigabyte(1))         // true
154 megabyte(1024).equals(gigabyte(1))         // false
155 terabyte(12).equals(gigabyte(12000))       // true
158 ### Formatting
160 Each unit prints a human-readable string, representing the amount of bytes in the given unit using the symbol specified in ISO IEC 80000-13:2008.
162 ```java
163 import static wtf.metio.storageunits.model.StorageUnits.*;
165 // default pattern '0.00'
166 terabyte(2).toString()                         // "2.00 TB"
167 gigabyte(1).add(megabyte(200)).toString()      // "1.20 GB"
168 petabyte(1).subtract(terabyte(250)).toString() // "0.75 PB"
170 // use custom pattern
171 kilobyte(212345).toString("0.0")                                    // "212345.0 kB"
172 gibibyte(2123458).asTebibyte().toString("#,###.000")                // "2,073.689 TiB"
173 kilobyte(120).asMegabyte().add(gigabyte(1)).toString("#,##0.00000") // "1,000.12000 MB"
175 // use custom pattern with specific Locale
176 kilobyte(212345).toString("0.0", Locale.GERMAN)                     // "212345,0 kB"
177 gibibyte(2123458).asTebibyte().toString("#,###.000", Locale.GERMAN) // "2.073,689 TiB"
179 // use custom format
180 Format customFormat = new DecimalFormat("#.00000");
181 terabyte(4).asTebibyte().toString(customFormat) // "3.63798 TiB"
183 // without creating unit type first
184 long numberOfBytes = 1_000_000_000_000_000L;
185 formatAsPetabyte(numberOfBytes) // "1.00 PB"
186 formatAsTerabyte(numberOfBytes) // "1000.00 TB"
187 formatAsPebibyte(numberOfBytes) // "0.89 PiB"
189 // use custom pattern
190 formatAsTerabyte(numberOfBytes, "#0.#####") // "1000 TB"
191 formatAsPebibyte(numberOfBytes, "#0.#####") // "0.88818 PiB"
193 // use custom pattern with specific Locale
194 formatAsTerabyte(numberOfBytes, "#0.#####", Locale.GERMAN) // "1000 TB"
195 formatAsPebibyte(numberOfBytes, "#0.#####", Locale.GERMAN) // "0,88818 PiB"
197 // use custom format
198 formatAsTerabyte(numberOfBytes, customFormat) // "1000.00000 TB"
199 formatAsPebibyte(numberOfBytes, customFormat) // ".88818 PiB"
202 ### Conversions
204 Each unit can be converted to each other unit without loss of information.
206 ```java
207 import static wtf.metio.storageunits.model.StorageUnits.*;
209 Megabyte unit = kilobyte(1000).asMegabyte() // "1.00 MB"
210 Kilobyte unit = gigabyte(12).asKilobyte()   // "12000000.00 kB"
211 Gigabyte unit = terabyte(1).asGigabyte()    // "1000.00 GB"
213 // convert to best-match
214 kilobyte(1100).asBestMatchingUnit()          // "1.10 MB"
215 kilobyte(1100).asBestMatchingBinaryUnit()    // "1.05 MiB"
216 kilobyte(1100).asBestMatchingDecimalUnit()   // "1.10 MB"
217 kilobyte(1100).asBestMatchingCommonUnit()    // "1.05 MB"
220 Each unit can be expressed as a fraction of another unit (precise up to 24 decimal places)
222 ```java
223 import static wtf.metio.storageunits.model.StorageUnits.*;
225 BigDecimal kilobytes = megabyte(1).inKilobyte()  // 1 000
226 BigInteger bytes = kibibyte(2).inByte()          // 2 048
227 BigDecimal terabytes = gigabyte(15).inTerabyte() // 0.015
230 ### Serialization/Converters/Mappers
232 Multiple custom serializers, converters, and mappers are available for all storage units.
234 #### Dozer
236 Use a [Dozer](https://dozermapper.github.io/) converter like this:
238 ```java
239 import static wtf.metio.storageunits.dozer.*;
241 DozerBeanMapperBuilder.create()
242         .withCustomConverter(new BigIntegerBinaryStorageUnitConverter())
243         .withCustomConverter(new BigIntegerDecimalStorageUnitConverter())
244         .withCustomConverter(new LongBinaryStorageUnitConverter())
245         .withCustomConverter(new LongDecimalStorageUnitConverter())
246         .build();
249 #### EclipseLink
251 Use any of the three converters like this:
253 ```java
254 import static wtf.metio.storageunits.eclipselink.*;
256 @Entity
257 public class HardDisk implements Serializable {
259     @Basic
260     @Converter (
261         name="binaryConverter",
262         converterClass=BinaryStorageUnitConverter.class
263     )
264     @Convert("binaryConverter")
265     public StorageUnit<?> getFreeSize() {
266         return freeSize;
267     }
269     @Basic
270     @Converter (
271         name="decimalConverter",
272         converterClass=DecimalyStorageUnitConverter.class
273     )
274     @Convert("decimalConverter")
275     public StorageUnit<?> getTotalSize() {
276         return totalSize;
277     }
282 #### Jackson
284 Use the provided `StorageUnitModule` like this:
286 ```java
287 import static wtf.metio.storageunits.jackson.*;
289 ObjectMapper objectMapper = new ObjectMapper();
290 objectMapper.registerModule(new StorageUnitModule()); // defaults to binary units
291 objectMapper.registerModule(new StorageUnitModule(StorageUnitModule.PreferredUnitType.BINARY));
292 objectMapper.registerModule(new StorageUnitModule(StorageUnitModule.PreferredUnitType.DECIMAL));
295 #### Jakarta
297 Use the provided `AttributeConverter`s like this:
299 ```java
300 import static wtf.metio.storageunits.jakarta.*;
302 @Entity
303 public class HardDisk implements Serializable {
305     @Convert(converter = BinaryStorageUnitConverter.class)
306     public StorageUnit<?> getFreeSize() {
307         return freeSize;
308     }
310     @Convert(converter = DecimalStorageUnitConverter.class)
311     public StorageUnit<?> getTotalSize() {
312         return totalSize;
313     }
318 #### MapStruct
320 Use any of the available mappers like this:
322 ```java
323 import static wtf.metio.storageunits.mapstruct.*;
325 @Mapper( uses = BigIntegerToBinaryUnitMapper.class )
326 public interface MovieMapper {
328      DestinationType toDestination(SourceType sourceValue);
333 #### ModelMapper
335 Use any of the available converters like this:
337 ```java
338 import static wtf.metio.storageunits.modelmapper.*;
340 modelMapper.addConverter(new BigIntegerToBinaryUnitConverter());
341 modelMapper.addConverter(new BigIntegerToDecimalUnitConverter());
342 modelMapper.addConverter(new LongToBinaryUnitConverter());
343 modelMapper.addConverter(new LongToDecimalUnitConverter());
344 modelMapper.addConverter(new StorageUnitToBigIntegerConverter());
347 #### MongoDB
349 Use any of the three codecs like this:
351 ```java
352 import static wtf.metio.storageunits.mongodb.*;
354 CodecRegistry binaryRegistry = CodecRegistries.fromCodecs(new BinaryStorageUnitCodec(), ...);
355 CodecRegistry decimalRegistry = CodecRegistries.fromCodecs(new DecimalStorageUnitCodec(), ...);
358 #### Orika
360 Use any of the provided converters like this:
362 ```java
363 import static wtf.metio.storageunits.orika.*;
365 ConverterFactory converterFactory = mapperFactory.getConverterFactory();
366 converterFactory.registerConverter(new BinaryStorageUnitConverter());
367 converterFactory.registerConverter(new DecimalStorageUnitConverter());
370 ### Integration
372 To use this project just declare the following dependency inside your POM:
374 ```xml
375 <dependencies>
376     <dependency>
377         <groupId>wtf.metio.storage-units</groupId>
378         <artifactId>storage-units-model</artifactId>
379         <version>${version.storage-units}</version>
380     </dependency>
382     <!-- Dozer ONLY -->
383     <dependency>
384         <groupId>wtf.metio.storage-units</groupId>
385         <artifactId>storage-units-dozer</artifactId>
386         <version>${version.storage-units}</version>
387     </dependency>
388     <!-- Dozer ONLY -->
390     <!-- EclipseLink ONLY -->
391     <dependency>
392         <groupId>wtf.metio.storage-units</groupId>
393         <artifactId>storage-units-eclipselink</artifactId>
394         <version>${version.storage-units}</version>
395     </dependency>
396     <!-- EclipseLink ONLY -->
398     <!-- Jackson ONLY -->
399     <dependency>
400         <groupId>wtf.metio.storage-units</groupId>
401         <artifactId>storage-units-jackson</artifactId>
402         <version>${version.storage-units}</version>
403     </dependency>
404     <!-- Jackson ONLY -->
406     <!-- Jakarta ONLY -->
407     <dependency>
408         <groupId>wtf.metio.storage-units</groupId>
409         <artifactId>storage-units-jakarta</artifactId>
410         <version>${version.storage-units}</version>
411     </dependency>
412     <!-- Jakarta ONLY -->
414     <!-- MapStruct ONLY -->
415     <dependency>
416         <groupId>wtf.metio.storage-units</groupId>
417         <artifactId>storage-units-mapstruct</artifactId>
418         <version>${version.storage-units}</version>
419     </dependency>
420     <!-- MapStruct ONLY -->
422     <!-- ModelMapper ONLY -->
423     <dependency>
424         <groupId>wtf.metio.storage-units</groupId>
425         <artifactId>storage-units-modelmapper</artifactId>
426         <version>${version.storage-units}</version>
427     </dependency>
428     <!-- ModelMapper ONLY -->
430     <!-- MongoDB ONLY -->
431     <dependency>
432         <groupId>wtf.metio.storage-units</groupId>
433         <artifactId>storage-units-mongodb</artifactId>
434         <version>${version.storage-units}</version>
435     </dependency>
436     <!-- MongoDB ONLY -->
438     <!-- Orika ONLY -->
439     <dependency>
440         <groupId>wtf.metio.storage-units</groupId>
441         <artifactId>storage-units-orika</artifactId>
442         <version>${version.storage-units}</version>
443     </dependency>
444     <!-- Orika ONLY -->
445 </dependencies>
448 Replace `${version.storage-units}` with the [latest release](https://search.maven.org/search?q=g:wtf.metio.storage-units).
450 ## Reference
452 Originally inspired by [Twitters util](https://github.com/twitter/util#space) package.
454 ## Alternatives
456 * [Byte Units](https://github.com/JakeWharton/byteunits)
457 * [triava](https://github.com/trivago/triava)
459 ## License
462 Permission to use, copy, modify, and/or distribute this software for any
463 purpose with or without fee is hereby granted.
465 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
466 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
467 FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
468 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
469 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
470 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
471 PERFORMANCE OF THIS SOFTWARE.