1   package com.atlassian.core.util;
2   
3   import java.text.DecimalFormat;
4   import java.text.NumberFormat;
5   
6   /**
7    * A class that contains utility methods for formatting the size of files into human
8    * readable form.
9    */
10  public class FileSize
11  {
12      public FileSize()
13      {
14          //need public constructor as this is used as a bean in Webwork's JSP taglibs (which don't handle static calls).
15      }
16  
17      private static final float KB_SIZE = 1024;
18      private static final float MB_SIZE = KB_SIZE * KB_SIZE;
19  
20      private static final String KB = " kB";
21      private static final String MB = " MB";
22  
23      /**
24       * Convenience method. Calls format(long filesize).
25       * @param   filesize  The size of the file in bytes.
26       * @return  The size in human readable form.
27       * @see #format(long)
28       */
29      public static String format(Long filesize)
30      {
31          return format(filesize.longValue());
32      }
33  
34      /**
35       * Format the size of a file in human readable form.  Anything less than a kilobyte
36       * is presented in kilobytes to one decimal place.  Anything between a kilobyte and a megabyte is
37       * presented in kilobytes to zero decimal places.  Anything greater than one megabyte is
38       * presented in megabytes to two decimal places.
39       * <p>
40       * eg.
41       * <ul>
42       *  <li>format(512) -> 0.5 kb
43       *  <li>format(1024) -> 1.0 kb
44       *  <li>format(2048) -> 2 kb
45       *  <li>format(1024 * 400) -> 400 kb
46       *  <li>format(1024 * 1024) -> 1024 kb
47       *  <li>format(1024 * 1024 * 1.2) -> 1.20 Mb
48       *  <li>format(1024 * 1024 * 20) -> 20.00 Mb
49       * </ul>
50       *
51       * @param   filesize  The size of the file in bytes.
52       * @return  The size in human readable form.
53       */
54      public static String format(long filesize)
55      {
56          // TODO: filesize = 1024 gives "1.0 kB", but filesize = 1025 gives "1 kB", this is kinda inconsistent.
57  
58          if (filesize > MB_SIZE)
59          {
60              return formatMB(filesize);
61          }
62          else if (filesize > KB_SIZE)
63          {
64              return formatKB(filesize);
65          }
66          else
67          {
68              return formatBytes(filesize);
69          }
70  
71      }
72  
73      private static String formatMB(long filesize)
74      {
75          NumberFormat mbFormat = new DecimalFormat();
76          mbFormat.setMinimumIntegerDigits(1);
77          mbFormat.setMaximumFractionDigits(2); //format 2 decimal places
78          mbFormat.setMinimumFractionDigits(2); //format 2 decimal places
79          float mbsize = (float) filesize / MB_SIZE;
80          return mbFormat.format(mbsize) + MB;
81      }
82  
83      private static String formatKB(long filesize)
84      {
85          long kbsize = Math.round((float) filesize / KB_SIZE); //format 0 decimal places
86          return String.valueOf(kbsize) + KB;
87      }
88  
89      private static String formatBytes(long filesize)
90      {
91          NumberFormat bFormat = new DecimalFormat();
92          bFormat.setMinimumIntegerDigits(1);
93          bFormat.setMaximumFractionDigits(1); //format 1 decimal places
94          bFormat.setMinimumFractionDigits(1); //format 1 decimal places
95          float mbsize = (float) filesize / KB_SIZE;
96          return bFormat.format(mbsize) + KB;
97      }
98  }