Formatting an Integer using ISO-prefixes for kB,MB,GB,... and kiB,MiB,GiB,
I looking for the function that prints file size on the mode-line in size-indication-mode. I have searched for size-indication-mode in the source but cannot find a code-references to it. So where is the function that prints for e开发者_StackOverflowxample 22k
when file is approximately 22 kilobytes big?
What about difference between - kilobytes (kB), 1000 bytes, and - kibibytes (KiB), 1024 bytes, as defined at
Shouldn't Emacs support both?
This is of course not that hard to write but why reinvent the wheel?
http://en.wikipedia.org/wiki/Kibibyte
I noticed that emacs dev (bzr) just go a new function, file-size-human-readable()
defined. It does just what I asked for.
Some emacs developer must have heard my call :)
See C-hf format-mode-line
RET, and C-hv mode-line-format
RET.
Enabling size-indication-mode
simply causes of %I
to be added into the buffer's local mode-line-format string, and the C function takes care of the rest.
You can use %i
instead to see the buffer size in bytes.
If you want something to which you can supply an arbitrary value, there's at least one elisp function along these lines provided with Emacs (in the ls-lisp
module):
C-hf ls-lisp-format-file-size
RET
Here's the function I use.
(defconst number-to-string-approx-suffixes
'("k" "M" "G" "T" "P" "E" "Z" "Y"))
(defun number-to-string-approx-suffix (n &optional binary)
"Return an approximate decimal representation of NUMBER as a string,
followed by a multiplier suffix (k, M, G, T, P, E, Z, Y). The representation
is at most 5 characters long for numbers between 0 and 10^19-5*10^16.
Uses a minus sign if negative.
NUMBER may be an integer or a floating point number.
If the optional argument BINARY is non-nil, use 1024 instead of 1000 as
the base multiplier."
(if (zerop n)
"0"
(let ((sign "")
(b (if binary 1024 1000))
(suffix "")
(bigger-suffixes number-to-string-approx-suffixes))
(if (< n 0)
(setq n (- n)
sign "-"))
(while (and (>= n 9999.5) (consp bigger-suffixes))
(setq n (/ n b) ; TODO: this is rounding down; nearest would be better
suffix (car bigger-suffixes)
bigger-suffixes (cdr bigger-suffixes)))
(concat sign
(if (integerp n)
(int-to-string n)
(number-to-string (floor n)))
suffix))))
I use it in the size column of the buffer menu.
(defvar Buffer-menu-buffer+size-shorten 'binary)
(defadvice Buffer-menu-buffer+size (before Buffer-menu-shorten-size
compile activate)
"Shorten the size column in a buffer menu by using multiplier suffixes
\(k, M, G, T\).
This is done only if `Buffer-menu-buffer+size-shorten' is non-nil.
If `Buffer-menu-buffer+size-shorten' is the symbol `binary', use binary
multipliers (powers of 1024). Otherwise use decimal (powers of 1000)
multipliers."
(if Buffer-menu-buffer+size-shorten
(let ((binary (eq Buffer-menu-buffer+size-shorten 'binary)))
(save-match-data
(if (string-match "^[0-9]+$" size)
(setq size (number-to-string-approx-suffix (string-to-number size)
binary)))))))
Ok, I hacked up a solution myself. Should be close to what size-indication-mode
provides
(defun number-to-iso-postfixed-string (number &optional binary)
"Convert NUMBER to ISO-postfixed string.
If BINARY is non-nil use bibytes prefixes KiB, MiB, GiB instead of
kB, MB, GB etc."
(let ((scale (if binary 1024.0 1000.0))
(postfix nil))
(concat (if (< number scale)
(if (zerop number) "0" (number-to-string number))
(format "%.1f"
(cond ((< number (expt scale 2)) (setq postfix "k") (/ number (expt scale 1)))
((< number (expt scale 3)) (setq postfix "M") (/ number (expt scale 2)))
((< number (expt scale 4)) (setq postfix "G") (/ number (expt scale 3)))
((< number (expt scale 5)) (setq postfix "T") (/ number (expt scale 4)))
((< number (expt scale 6)) (setq postfix "P") (/ number (expt scale 5)))
((< number (expt scale 7)) (setq postfix "E") (/ number (expt scale 6)))
(t
number)
)))
postfix
(when (and postfix binary) "i"))))
;; Use: (number-to-iso-postfixed-string 999 nil)
;; Use: (number-to-iso-postfixed-string 1001 nil)
;; Use: (number-to-iso-postfixed-string 1024)
;; Use: (number-to-iso-postfixed-string 1024 t)
;; Use: (number-to-iso-postfixed-string (* 1024 1024) t)
;; Use: (number-to-iso-postfixed-string (* 1024 1023) t)
;; Use: (number-to-iso-postfixed-string (* 1024 1025) t)
;; Use: (number-to-iso-postfixed-string (* 1024.0 1024 1025) t)
精彩评论