2 SPDX-FileCopyrightText: The Storage-Units Authors
3 SPDX-License-Identifier: 0BSD
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
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 |
35 | Name | Symbol | Exponential | Absolute |
36 |-----------|--------|----------------------|----------------------------------------|
37 | Byte | B | 10<sup>0</sup> Byte | 1 Byte |
38 | Kilobyte | KB | 10<sup>3</sup> Byte | 1 000 Byte |
39 | Megabyte | MB | 10<sup>6</sup> Byte | 1 000 000 Byte |
40 | Gigabyte | GB | 10<sup>9</sup> Byte | 1 000 000 000 Byte |
41 | Terabyte | TB | 10<sup>12</sup> Byte | 1 000 000 000 000 Byte |
42 | Petabyte | PB | 10<sup>15</sup> Byte | 1 000 000 000 000 000 Byte |
43 | Exabyte | EB | 10<sup>18</sup> Byte | 1 000 000 000 000 000 000 Byte |
44 | Zettabyte | ZB | 10<sup>21</sup> Byte | 1 000 000 000 000 000 000 000 Byte |
45 | Yottabyte | YB | 10<sup>24</sup> Byte | 1 000 000 000 000 000 000 000 000 Byte |
51 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`.
55 Kilobyte unit = Kilobyte.valueOf(500) // 500 Byte or "0.50 kB"
56 Kibibyte unit = Kibibyte.valueOf(512) // 512 Byte or "0.50 KiB"
58 Megabyte unit = Megabyte.valueOf(1_000_000) // 1 000 000 Byte or "1.00 MB"
59 Mebibyte unit = Mebibyte.valueOf(1_048_576) // 1 048 576 Byte or "1.00 MiB"
62 Kilobyte unit = Kilobyte.valueOf(BigInteger.valueOf(500)) // 500 Byte or "0.50 kB"
63 Kibibyte unit = Kibibyte.valueOf(BigInteger.valueOf(512)) // 512 Byte or "0.50 KiB"
65 Megabyte unit = Megabyte.valueOf(BigInteger.valueOf(1000000)) // 1 000 000 Byte or "1.00 MB"
66 Mebibyte unit = Mebibyte.valueOf(BigInteger.valueOf(1_048_576)) // 1 048 576 Byte or "1.00 MB"
69 The `StorageUnits` class offers three factory methods that automatically pick the best-matching unit for a given number of bytes.
75 StorageUnit<?> unit = StorageUnits.binaryValueOf(256) // Kibibyte (0.25 KiB)
76 StorageUnit<?> unit = StorageUnits.binaryValueOf(1048576) // Mebibyte (1.00 MiB)
79 StorageUnit<?> unit = StorageUnits.binaryValueOf(BigInteger.valueOf(256)) // Kibibyte (0.25 MiB)
80 StorageUnit<?> unit = StorageUnits.binaryValueOf(BigInteger.valueOf(1048576)) // Mebibyte (1.00 MiB)
87 StorageUnit<?> unit = StorageUnits.decimalValueOf(120000) // Kilobyte (120.00 kB)
88 StorageUnit<?> unit = StorageUnits.decimalValueOf(1000000) // Megabyte (1.00 MB)
91 StorageUnit<?> unit = StorageUnits.decimalValueOf(BigInteger.valueOf(120000)) // Kilobyte (120.00 kB)
92 StorageUnit<?> unit = StorageUnits.decimalValueOf(BigInteger.valueOf(1000000)) // Megabyte (1.00 MB)
95 Additionally high-level factory methods are also available in the `StorageUnits` class.
98 import static wtf.metio.storageunits.model.StorageUnits.*;
100 Kibibyte unit = kibibyte(1) // 1 024 Byte
101 Mebibyte unit = mebibyte(1) // 1 048 576 Byte
102 Gibibyte unit = gibibyte(1) // 1 073 741 824 Byte
103 Tebibyte unit = tebibyte(1) // 1 099 511 627 776 Byte
104 Pebibyte unit = pebibyte(1) // 1 125 899 906 842 624 Byte
105 Exbibyte unit = exbibyte(1) // 1 152 921 504 606 846 976 Byte
106 Zebibyte unit = zebibyte(1) // 1 180 591 620 717 411 303 424 Byte
107 Yobibyte unit = yobibyte(1) // 1 208 925 819 614 629 174 706 176 Byte
109 Kilobyte unit = kilobyte(1) // 1 000 Byte
110 Megabyte unit = megabyte(1) // 1 000 000 Byte
111 Gigabyte unit = gigabyte(1) // 1 000 000 000 Byte
112 Terabyte unit = terabyte(1) // 1 000 000 000 000 Byte
113 Petabyte unit = petabyte(1) // 1 000 000 000 000 000 Byte
114 Exabyte unit = exabyte(1) // 1 000 000 000 000 000 000 Byte
115 Zettabyte unit = zettabyte(1) // 1 000 000 000 000 000 000 000 Byte
116 Yottabyte unit = yottabyte(1) // 1 000 000 000 000 000 000 000 000 Byte
119 ### Add, Subtract, Multiply, Divide
121 Each unit implements the basic four math operations. All operations retain their original type, e.g. `[Kilobyte] + [Megabyte] = [Kilobyte]`
124 import static wtf.metio.storageunits.model.StorageUnits.*;
126 kilobyte(4).add(kilobyte(8)) // 4 Kilobyte + 8 Kilobyte = 12 Kilobyte = 12 000 Byte
127 kibibyte(1).add(1024) // 1 Kibibyte + 1 024 Byte = 2 Kibibyte = 2 048 Byte
128 kibibyte(1).subtract(24) // 1 024 Byte - 24 Byte = 1 000 Byte
129 megabyte(5).subtract(kilobyte(500)) // 5 Megabyte - 500 Kilobyte = 4.5 Megabyte = 4 500 Kilobyte = 4 500 000 Byte
130 gigabyte(1).multiply(5) // 1 Gigabyte times 5 = 5 Gigabyte
131 terabyte(1).divide(5) // 1 Terabyte divided by 5 = 0.2 Terabyte = 200 Gigabyte
134 ### Comparison & Equality
136 Each unit is comparable to each other unit.
139 import static wtf.metio.storageunits.model.StorageUnits.*;
141 kibibyte(1024).compareTo(mebibyte(1)) == 0 // true
142 kibibyte(1000).compareTo(mebibyte(1)) == 0 // false
143 petabyte(3).compareTo(terabyte(3000)) == 0 // true
145 megabyte(1000).equals(gigabyte(1)) // true
146 megabyte(1024).equals(gigabyte(1)) // false
147 terabyte(12).equals(gigabyte(12000)) // true
152 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.
155 import static wtf.metio.storageunits.model.StorageUnits.*;
157 // default pattern '0.00'
158 terabyte(2).toString() // "2.00 TB"
159 gigabyte(1).add(megabyte(200)).toString() // "1.20 GB"
160 petabyte(1).subtract(terabyte(250)).toString() // "0.75 PB"
162 // use custom pattern
163 kilobyte(212345).toString("0.0") // "212345.0 kB"
164 gibibyte(2123458).asTebibyte().toString("#,###.000") // "2,073.689 TiB"
165 kilobyte(120).asMegabyte().add(gigabyte(1)).toString("#,##0.00000") // "1,000.12000 MB"
167 // use custom pattern with specific Locale
168 kilobyte(212345).toString("0.0", Locale.GERMAN) // "212345,0 kB"
169 gibibyte(2123458).asTebibyte().toString("#,###.000", Locale.GERMAN) // "2.073,689 TiB"
172 Format customFormat = new DecimalFormat("#.00000");
173 terabyte(4).asTebibyte().toString(customFormat) // "3.63798 TiB"
175 // without creating unit type first
176 long numberOfBytes = 1_000_000_000_000_000L;
177 formatAsPetabyte(numberOfBytes) // "1.00 PB"
178 formatAsTerabyte(numberOfBytes) // "1000.00 TB"
179 formatAsPebibyte(numberOfBytes) // "0.89 PiB"
181 // use custom pattern
182 formatAsTerabyte(numberOfBytes, "#0.#####") // "1000 TB"
183 formatAsPebibyte(numberOfBytes, "#0.#####") // "0.88818 PiB"
185 // use custom pattern with specific Locale
186 formatAsTerabyte(numberOfBytes, "#0.#####", Locale.GERMAN) // "1000 TB"
187 formatAsPebibyte(numberOfBytes, "#0.#####", Locale.GERMAN) // "0,88818 PiB"
190 formatAsTerabyte(numberOfBytes, customFormat) // "1000.00000 TB"
191 formatAsPebibyte(numberOfBytes, customFormat) // ".88818 PiB"
196 Each unit can be converted to each other unit without loss of information.
199 import static wtf.metio.storageunits.model.StorageUnits.*;
201 Megabyte unit = kilobyte(1000).asMegabyte() // "1.00 MB"
202 Kilobyte unit = gigabyte(12).asKilobyte() // "12000000.00 kB"
203 Gigabyte unit = terabyte(1).asGigabyte() // "1000.00 GB"
205 // convert to best-match
206 kilobyte(1100).asBestMatchingUnit() // "1.10 MB"
207 kilobyte(1100).asBestMatchingBinaryUnit() // "1.05 MiB"
208 kilobyte(1100).asBestMatchingDecimalUnit() // "1.10 MB"
209 kilobyte(1100).asBestMatchingCommonUnit() // "1.05 MB"
212 Each unit can be expressed as a fraction of another unit (precise up to 24 decimal places)
215 import static wtf.metio.storageunits.model.StorageUnits.*;
217 BigDecimal kilobytes = megabyte(1).inKilobyte() // 1 000
218 BigInteger bytes = kibibyte(2).inByte() // 2 048
219 BigDecimal terabytes = gigabyte(15).inTerabyte() // 0.015
222 ### Serialization/Converters/Mappers
224 Multiple custom serializers, converters, and mappers are available for all storage units.
228 Use a [Dozer](https://dozermapper.github.io/) converter like this:
231 import static wtf.metio.storageunits.dozer.*;
233 DozerBeanMapperBuilder.create()
234 .withCustomConverter(new BigIntegerBinaryStorageUnitConverter())
235 .withCustomConverter(new BigIntegerDecimalStorageUnitConverter())
236 .withCustomConverter(new LongBinaryStorageUnitConverter())
237 .withCustomConverter(new LongDecimalStorageUnitConverter())
243 Use any of the three converters like this:
246 import static wtf.metio.storageunits.eclipselink.*;
249 public class HardDisk implements Serializable {
253 name="binaryConverter",
254 converterClass=BinaryStorageUnitConverter.class
256 @Convert("binaryConverter")
257 public StorageUnit<?> getFreeSize() {
263 name="decimalConverter",
264 converterClass=DecimalyStorageUnitConverter.class
266 @Convert("decimalConverter")
267 public StorageUnit<?> getTotalSize() {
276 Use the provided `StorageUnitModule` like this:
279 import static wtf.metio.storageunits.jackson.*;
281 ObjectMapper objectMapper = new ObjectMapper();
282 objectMapper.registerModule(new StorageUnitModule()); // defaults to binary units
283 objectMapper.registerModule(new StorageUnitModule(StorageUnitModule.PreferredUnitType.BINARY));
284 objectMapper.registerModule(new StorageUnitModule(StorageUnitModule.PreferredUnitType.DECIMAL));
289 Use the provided `AttributeConverter`s like this:
292 import static wtf.metio.storageunits.jakarta.*;
295 public class HardDisk implements Serializable {
297 @Convert(converter = BinaryStorageUnitConverter.class)
298 public StorageUnit<?> getFreeSize() {
302 @Convert(converter = DecimalStorageUnitConverter.class)
303 public StorageUnit<?> getTotalSize() {
312 Use any of the available mappers like this:
315 import static wtf.metio.storageunits.mapstruct.*;
317 @Mapper( uses = BigIntegerToBinaryUnitMapper.class )
318 public interface MovieMapper {
320 DestinationType toDestination(SourceType sourceValue);
327 Use any of the available converters like this:
330 import static wtf.metio.storageunits.modelmapper.*;
332 modelMapper.addConverter(new BigIntegerToBinaryUnitConverter());
333 modelMapper.addConverter(new BigIntegerToDecimalUnitConverter());
334 modelMapper.addConverter(new LongToBinaryUnitConverter());
335 modelMapper.addConverter(new LongToDecimalUnitConverter());
336 modelMapper.addConverter(new StorageUnitToBigIntegerConverter());
341 Use any of the three codecs like this:
344 import static wtf.metio.storageunits.mongodb.*;
346 CodecRegistry binaryRegistry = CodecRegistries.fromCodecs(new BinaryStorageUnitCodec(), ...);
347 CodecRegistry decimalRegistry = CodecRegistries.fromCodecs(new DecimalStorageUnitCodec(), ...);
352 Use any of the provided converters like this:
355 import static wtf.metio.storageunits.orika.*;
357 ConverterFactory converterFactory = mapperFactory.getConverterFactory();
358 converterFactory.registerConverter(new BinaryStorageUnitConverter());
359 converterFactory.registerConverter(new DecimalStorageUnitConverter());
364 To use this project just declare the following dependency inside your POM:
369 <groupId>wtf.metio.storage-units</groupId>
370 <artifactId>storage-units-model</artifactId>
371 <version>${version.storage-units}</version>
376 <groupId>wtf.metio.storage-units</groupId>
377 <artifactId>storage-units-dozer</artifactId>
378 <version>${version.storage-units}</version>
382 <!-- EclipseLink ONLY -->
384 <groupId>wtf.metio.storage-units</groupId>
385 <artifactId>storage-units-eclipselink</artifactId>
386 <version>${version.storage-units}</version>
388 <!-- EclipseLink ONLY -->
390 <!-- Jackson ONLY -->
392 <groupId>wtf.metio.storage-units</groupId>
393 <artifactId>storage-units-jackson</artifactId>
394 <version>${version.storage-units}</version>
396 <!-- Jackson ONLY -->
398 <!-- Jakarta ONLY -->
400 <groupId>wtf.metio.storage-units</groupId>
401 <artifactId>storage-units-jakarta</artifactId>
402 <version>${version.storage-units}</version>
404 <!-- Jakarta ONLY -->
406 <!-- MapStruct ONLY -->
408 <groupId>wtf.metio.storage-units</groupId>
409 <artifactId>storage-units-mapstruct</artifactId>
410 <version>${version.storage-units}</version>
412 <!-- MapStruct ONLY -->
414 <!-- ModelMapper ONLY -->
416 <groupId>wtf.metio.storage-units</groupId>
417 <artifactId>storage-units-modelmapper</artifactId>
418 <version>${version.storage-units}</version>
420 <!-- ModelMapper ONLY -->
422 <!-- MongoDB ONLY -->
424 <groupId>wtf.metio.storage-units</groupId>
425 <artifactId>storage-units-mongodb</artifactId>
426 <version>${version.storage-units}</version>
428 <!-- MongoDB ONLY -->
432 <groupId>wtf.metio.storage-units</groupId>
433 <artifactId>storage-units-orika</artifactId>
434 <version>${version.storage-units}</version>
440 Replace `${version.storage-units}` with the [latest release](https://search.maven.org/search?q=g:wtf.metio.storage-units).
444 Originally inspired by [Twitters util](https://github.com/twitter/util#space) package.
448 * [Byte Units](https://github.com/JakeWharton/byteunits)
449 * [triava](https://github.com/trivago/triava)
454 Permission to use, copy, modify, and/or distribute this software for any
455 purpose with or without fee is hereby granted.
457 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
458 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
459 FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
460 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
461 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
462 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
463 PERFORMANCE OF THIS SOFTWARE.