2 SPDX-FileCopyrightText: The Storage-Units Authors
3 SPDX-License-Identifier: 0BSD
6 # Storage-Units [![Chat](https://img.shields.io/badge/matrix-%23talk.metio:matrix.org-brightgreen.svg?style=social&label=Matrix)](https://matrix.to/#/#talk.metio:matrix.org)
8 Storage units according to ISO IEC 80000-13:2008 implemented in Java.
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
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 |
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`.
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"
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"
73 The `StorageUnits` class offers three factory methods that automatically pick the best-matching unit for a given number of bytes.
79 StorageUnit<?> unit = StorageUnits.binaryValueOf(256) // Kibibyte (0.25 KiB)
80 StorageUnit<?> unit = StorageUnits.binaryValueOf(1048576) // Mebibyte (1.00 MiB)
83 StorageUnit<?> unit = StorageUnits.binaryValueOf(BigInteger.valueOf(256)) // Kibibyte (0.25 MiB)
84 StorageUnit<?> unit = StorageUnits.binaryValueOf(BigInteger.valueOf(1048576)) // Mebibyte (1.00 MiB)
91 StorageUnit<?> unit = StorageUnits.decimalValueOf(120000) // Kilobyte (120.00 kB)
92 StorageUnit<?> unit = StorageUnits.decimalValueOf(1000000) // Megabyte (1.00 MB)
95 StorageUnit<?> unit = StorageUnits.decimalValueOf(BigInteger.valueOf(120000)) // Kilobyte (120.00 kB)
96 StorageUnit<?> unit = StorageUnits.decimalValueOf(BigInteger.valueOf(1000000)) // Megabyte (1.00 MB)
99 Additionally high-level factory methods are also available in the `StorageUnits` class.
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]`
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.
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
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.
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"
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"
198 formatAsTerabyte(numberOfBytes, customFormat) // "1000.00000 TB"
199 formatAsPebibyte(numberOfBytes, customFormat) // ".88818 PiB"
204 Each unit can be converted to each other unit without loss of information.
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"
219 Each unit can be expressed as a fraction of another unit (precise up to 24 decimal places)
222 import static wtf.metio.storageunits.model.StorageUnits.*;
224 BigDecimal kilobytes = megabyte(1).inKilobyte() // 1 000
225 BigInteger bytes = kibibyte(2).inByte() // 2 048
226 BigDecimal terabytes = gigabyte(15).inTerabyte() // 0.015
229 ### Serialization/Converters/Mappers
231 Multiple custom serializers, converters, and mappers are available for all storage units.
235 Use a [Dozer](https://dozermapper.github.io/) converter like this:
238 import static wtf.metio.storageunits.dozer.*;
240 DozerBeanMapperBuilder.create()
241 .withCustomConverter(new BigIntegerBinaryStorageUnitConverter())
242 .withCustomConverter(new BigIntegerDecimalStorageUnitConverter())
243 .withCustomConverter(new LongBinaryStorageUnitConverter())
244 .withCustomConverter(new LongDecimalStorageUnitConverter())
250 Use any of the three converters like this:
253 import static wtf.metio.storageunits.eclipselink.*;
256 public class HardDisk implements Serializable {
260 name="binaryConverter",
261 converterClass=BinaryStorageUnitConverter.class
263 @Convert("binaryConverter")
264 public StorageUnit<?> getFreeSize() {
270 name="decimalConverter",
271 converterClass=DecimalyStorageUnitConverter.class
273 @Convert("decimalConverter")
274 public StorageUnit<?> getTotalSize() {
283 Use a [GSON](https://github.com/google/gson) serializer/deserializer like this:
286 import static wtf.metio.storageunits.gson.*;
289 .registerTypeHierarchyAdapter(StorageUnit.class, new StorageUnitSerializer())
290 .registerTypeHierarchyAdapter(StorageUnit.class, new BinaryStorageUnitDeserializer())
291 .registerTypeHierarchyAdapter(StorageUnit.class, new DecimalStorageUnitDeserializer())
297 Use the provided `StorageUnitModule` like this:
300 import static wtf.metio.storageunits.jackson.*;
302 ObjectMapper objectMapper = new ObjectMapper();
303 objectMapper.registerModule(new StorageUnitModule()); // defaults to binary units
304 objectMapper.registerModule(new StorageUnitModule(StorageUnitModule.PreferredUnitType.BINARY));
305 objectMapper.registerModule(new StorageUnitModule(StorageUnitModule.PreferredUnitType.DECIMAL));
310 Use the provided `AttributeConverter`s like this:
313 import static wtf.metio.storageunits.jakarta.*;
316 public class HardDisk implements Serializable {
318 @Convert(converter = BinaryStorageUnitConverter.class)
319 public StorageUnit<?> getFreeSize() {
323 @Convert(converter = DecimalStorageUnitConverter.class)
324 public StorageUnit<?> getTotalSize() {
333 Use any of the available mappers like this:
336 import static wtf.metio.storageunits.mapstruct.*;
338 @Mapper( uses = BigIntegerToBinaryUnitMapper.class )
339 public interface MovieMapper {
341 DestinationType toDestination(SourceType sourceValue);
348 Use any of the available converters like this:
351 import static wtf.metio.storageunits.modelmapper.*;
353 modelMapper.addConverter(new BigIntegerToBinaryUnitConverter());
354 modelMapper.addConverter(new BigIntegerToDecimalUnitConverter());
355 modelMapper.addConverter(new LongToBinaryUnitConverter());
356 modelMapper.addConverter(new LongToDecimalUnitConverter());
357 modelMapper.addConverter(new StorageUnitToBigIntegerConverter());
362 Use any of the three codecs like this:
365 import static wtf.metio.storageunits.mongodb.*;
367 CodecRegistry binaryRegistry = CodecRegistries.fromCodecs(new BinaryStorageUnitCodec(), ...);
368 CodecRegistry decimalRegistry = CodecRegistries.fromCodecs(new DecimalStorageUnitCodec(), ...);
373 Use any of the provided converters like this:
376 import static wtf.metio.storageunits.orika.*;
378 ConverterFactory converterFactory = mapperFactory.getConverterFactory();
379 converterFactory.registerConverter(new BinaryStorageUnitConverter());
380 converterFactory.registerConverter(new DecimalStorageUnitConverter());
385 To use this project just declare the following dependency inside your POM:
390 <groupId>wtf.metio.storage-units</groupId>
391 <artifactId>storage-units-model</artifactId>
392 <version>${version.storage-units}</version>
397 <groupId>wtf.metio.storage-units</groupId>
398 <artifactId>storage-units-dozer</artifactId>
399 <version>${version.storage-units}</version>
403 <!-- EclipseLink ONLY -->
405 <groupId>wtf.metio.storage-units</groupId>
406 <artifactId>storage-units-eclipselink</artifactId>
407 <version>${version.storage-units}</version>
409 <!-- EclipseLink ONLY -->
413 <groupId>wtf.metio.storage-units</groupId>
414 <artifactId>storage-units-gson</artifactId>
415 <version>${version.storage-units}</version>
419 <!-- Jackson ONLY -->
421 <groupId>wtf.metio.storage-units</groupId>
422 <artifactId>storage-units-jackson</artifactId>
423 <version>${version.storage-units}</version>
425 <!-- Jackson ONLY -->
427 <!-- Jakarta ONLY -->
429 <groupId>wtf.metio.storage-units</groupId>
430 <artifactId>storage-units-jakarta</artifactId>
431 <version>${version.storage-units}</version>
433 <!-- Jakarta ONLY -->
435 <!-- MapStruct ONLY -->
437 <groupId>wtf.metio.storage-units</groupId>
438 <artifactId>storage-units-mapstruct</artifactId>
439 <version>${version.storage-units}</version>
441 <!-- MapStruct ONLY -->
443 <!-- ModelMapper ONLY -->
445 <groupId>wtf.metio.storage-units</groupId>
446 <artifactId>storage-units-modelmapper</artifactId>
447 <version>${version.storage-units}</version>
449 <!-- ModelMapper ONLY -->
451 <!-- MongoDB ONLY -->
453 <groupId>wtf.metio.storage-units</groupId>
454 <artifactId>storage-units-mongodb</artifactId>
455 <version>${version.storage-units}</version>
457 <!-- MongoDB ONLY -->
461 <groupId>wtf.metio.storage-units</groupId>
462 <artifactId>storage-units-orika</artifactId>
463 <version>${version.storage-units}</version>
469 Replace `${version.storage-units}` with the [latest release](https://central.sonatype.com/namespace/wtf.metio.storage-units).
473 Originally inspired by [Twitters util](https://github.com/twitter/util#space) package.
477 * [Byte Units](https://github.com/JakeWharton/byteunits)
478 * [triava](https://github.com/trivago/triava)