format & docs
[storage-units.git] / README.md
blob6b7dd900cbf844d5712559acee17fc61fa61ec1f
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
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 |
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 |
47 ## Usage
49 ### Factories
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`.
53 ```java
54 // 'long' based
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"
61 // 'BigInteger' based
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"
67 ```
69 The `StorageUnits` class offers three factory methods that automatically pick the best-matching unit for a given number of bytes.
71 #### Binary Units
73 ```java
74 // 'long' based
75 StorageUnit<?> unit = StorageUnits.binaryValueOf(256)                         // Kibibyte (0.25 KiB)
76         StorageUnit<?> unit = StorageUnits.binaryValueOf(1048576)                     // Mebibyte (1.00 MiB)
78 // 'BigInteger' based
79         StorageUnit<?> unit = StorageUnits.binaryValueOf(BigInteger.valueOf(256))     // Kibibyte (0.25 MiB)
80         StorageUnit<?> unit = StorageUnits.binaryValueOf(BigInteger.valueOf(1048576)) // Mebibyte (1.00 MiB)
81 ```
83 #### Decimal Units
85 ```java
86 // 'long' based
87 StorageUnit<?> unit = StorageUnits.decimalValueOf(120000)                      // Kilobyte (120.00 kB)
88         StorageUnit<?> unit = StorageUnits.decimalValueOf(1000000)                     // Megabyte (1.00 MB)
90 // 'BigInteger' based
91         StorageUnit<?> unit = StorageUnits.decimalValueOf(BigInteger.valueOf(120000))  // Kilobyte (120.00 kB)
92         StorageUnit<?> unit = StorageUnits.decimalValueOf(BigInteger.valueOf(1000000)) // Megabyte (1.00 MB)
93 ```
95 Additionally high-level factory methods are also available in the `StorageUnits` class.
97 ```java
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]`
123 ```java
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.
138 ```java
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
150 ### Formatting
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.
154 ```java
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"
171 // use custom format
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"
189 // use custom format
190         formatAsTerabyte(numberOfBytes, customFormat) // "1000.00000 TB"
191         formatAsPebibyte(numberOfBytes, customFormat) // ".88818 PiB"
194 ### Conversions
196 Each unit can be converted to each other unit without loss of information.
198 ```java
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)
214 ```java
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.
226 #### Dozer
228 Use a [Dozer](https://dozermapper.github.io/) converter like this:
230 ```java
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())
238         .build();
241 #### EclipseLink
243 Use any of the three converters like this:
245 ```java
246 import static wtf.metio.storageunits.eclipselink.*;
248 @Entity
249 public class HardDisk implements Serializable {
251     @Basic
252     @Converter (
253         name="binaryConverter",
254         converterClass=BinaryStorageUnitConverter.class
255     )
256     @Convert("binaryConverter")
257     public StorageUnit<?> getFreeSize() {
258         return freeSize;
259     }
261     @Basic
262     @Converter (
263         name="decimalConverter",
264         converterClass=DecimalyStorageUnitConverter.class
265     )
266     @Convert("decimalConverter")
267     public StorageUnit<?> getTotalSize() {
268         return totalSize;
269     }
274 #### Jackson
276 Use the provided `StorageUnitModule` like this:
278 ```java
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));
287 #### Jakarta
289 Use the provided `AttributeConverter`s like this:
291 ```java
292 import static wtf.metio.storageunits.jakarta.*;
294 @Entity
295 public class HardDisk implements Serializable {
297     @Convert(converter = BinaryStorageUnitConverter.class)
298     public StorageUnit<?> getFreeSize() {
299         return freeSize;
300     }
302     @Convert(converter = DecimalStorageUnitConverter.class)
303     public StorageUnit<?> getTotalSize() {
304         return totalSize;
305     }
310 #### MapStruct
312 Use any of the available mappers like this:
314 ```java
315 import static wtf.metio.storageunits.mapstruct.*;
317 @Mapper( uses = BigIntegerToBinaryUnitMapper.class )
318 public interface MovieMapper {
320      DestinationType toDestination(SourceType sourceValue);
325 #### ModelMapper
327 Use any of the available converters like this:
329 ```java
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());
339 #### MongoDB
341 Use any of the three codecs like this:
343 ```java
344 import static wtf.metio.storageunits.mongodb.*;
346 CodecRegistry binaryRegistry = CodecRegistries.fromCodecs(new BinaryStorageUnitCodec(), ...);
347 CodecRegistry decimalRegistry = CodecRegistries.fromCodecs(new DecimalStorageUnitCodec(), ...);
350 #### Orika
352 Use any of the provided converters like this:
354 ```java
355 import static wtf.metio.storageunits.orika.*;
357 ConverterFactory converterFactory = mapperFactory.getConverterFactory();
358 converterFactory.registerConverter(new BinaryStorageUnitConverter());
359 converterFactory.registerConverter(new DecimalStorageUnitConverter());
362 ### Integration
364 To use this project just declare the following dependency inside your POM:
366 ```xml
367 <dependencies>
368     <dependency>
369         <groupId>wtf.metio.storage-units</groupId>
370         <artifactId>storage-units-model</artifactId>
371         <version>${version.storage-units}</version>
372     </dependency>
374     <!-- Dozer ONLY -->
375     <dependency>
376         <groupId>wtf.metio.storage-units</groupId>
377         <artifactId>storage-units-dozer</artifactId>
378         <version>${version.storage-units}</version>
379     </dependency>
380     <!-- Dozer ONLY -->
382     <!-- EclipseLink ONLY -->
383     <dependency>
384         <groupId>wtf.metio.storage-units</groupId>
385         <artifactId>storage-units-eclipselink</artifactId>
386         <version>${version.storage-units}</version>
387     </dependency>
388     <!-- EclipseLink ONLY -->
390     <!-- Jackson ONLY -->
391     <dependency>
392         <groupId>wtf.metio.storage-units</groupId>
393         <artifactId>storage-units-jackson</artifactId>
394         <version>${version.storage-units}</version>
395     </dependency>
396     <!-- Jackson ONLY -->
398     <!-- Jakarta ONLY -->
399     <dependency>
400         <groupId>wtf.metio.storage-units</groupId>
401         <artifactId>storage-units-jakarta</artifactId>
402         <version>${version.storage-units}</version>
403     </dependency>
404     <!-- Jakarta ONLY -->
406     <!-- MapStruct ONLY -->
407     <dependency>
408         <groupId>wtf.metio.storage-units</groupId>
409         <artifactId>storage-units-mapstruct</artifactId>
410         <version>${version.storage-units}</version>
411     </dependency>
412     <!-- MapStruct ONLY -->
414     <!-- ModelMapper ONLY -->
415     <dependency>
416         <groupId>wtf.metio.storage-units</groupId>
417         <artifactId>storage-units-modelmapper</artifactId>
418         <version>${version.storage-units}</version>
419     </dependency>
420     <!-- ModelMapper ONLY -->
422     <!-- MongoDB ONLY -->
423     <dependency>
424         <groupId>wtf.metio.storage-units</groupId>
425         <artifactId>storage-units-mongodb</artifactId>
426         <version>${version.storage-units}</version>
427     </dependency>
428     <!-- MongoDB ONLY -->
430     <!-- Orika ONLY -->
431     <dependency>
432         <groupId>wtf.metio.storage-units</groupId>
433         <artifactId>storage-units-orika</artifactId>
434         <version>${version.storage-units}</version>
435     </dependency>
436     <!-- Orika ONLY -->
437 </dependencies>
440 Replace `${version.storage-units}` with the [latest release](https://search.maven.org/search?q=g:wtf.metio.storageunits).
442 ## Reference
444 Originally inspired by [Twitters util](https://github.com/twitter/util#space) package.
446 ## Alternatives
448 * [Byte Units](https://github.com/JakeWharton/byteunits)
449 * [triava](https://github.com/trivago/triava)
451 ## License
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.