Skip to content

Commit 0d46603

Browse files
committed
<demo><bytes><字节转换>
1 parent 8a1a570 commit 0d46603

File tree

3 files changed

+281
-0
lines changed

3 files changed

+281
-0
lines changed

demo/bytes/README.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Bytes
2+
3+
- Format bytes integer to human readable bytes string.
4+
- Parse human readable bytes string to bytes integer.
5+
6+
### Format
7+
8+
```go
9+
println(bytes.Format(13231323))
10+
```
11+
12+
`12.62MB`
13+
14+
### Parse
15+
16+
```go
17+
b, _ = Parse("2M")
18+
println(b)
19+
```
20+
21+
`2097152`

demo/bytes/bytes.go

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package bytes
2+
3+
import (
4+
"fmt"
5+
"regexp"
6+
"strconv"
7+
)
8+
9+
type (
10+
// Bytes struct
11+
Bytes struct{}
12+
)
13+
14+
const (
15+
_ = 1.0 << (10 * iota) // ignore first value by assigning to blank identifier
16+
KB
17+
MB
18+
GB
19+
TB
20+
PB
21+
EB
22+
)
23+
24+
var (
25+
pattern = regexp.MustCompile(`(?i)^(-?\d+(?:\.\d+)?)([KMGTPE]B?|B?)$`)
26+
global = New()
27+
)
28+
29+
// New creates a Bytes instance.
30+
func New() *Bytes {
31+
return &Bytes{}
32+
}
33+
34+
// Format formats bytes integer to human readable string.
35+
// For example, 31323 bytes will return 30.59KB.
36+
func (*Bytes) Format(b int64) string {
37+
multiple := ""
38+
value := float64(b)
39+
40+
switch {
41+
case b >= EB:
42+
value /= EB
43+
multiple = "EB"
44+
case b >= PB:
45+
value /= PB
46+
multiple = "PB"
47+
case b >= TB:
48+
value /= TB
49+
multiple = "TB"
50+
case b >= GB:
51+
value /= GB
52+
multiple = "GB"
53+
case b >= MB:
54+
value /= MB
55+
multiple = "MB"
56+
case b >= KB:
57+
value /= KB
58+
multiple = "KB"
59+
case b == 0:
60+
return "0"
61+
default:
62+
return strconv.FormatInt(b, 10) + "B"
63+
}
64+
65+
return fmt.Sprintf("%.2f%s", value, multiple)
66+
}
67+
68+
// Parse parses human readable bytes string to bytes integer.
69+
// For example, 6GB (6G is also valid) will return 6442450944.
70+
func (*Bytes) Parse(value string) (i int64, err error) {
71+
parts := pattern.FindStringSubmatch(value)
72+
if len(parts) < 3 {
73+
return 0, fmt.Errorf("error parsing value=%s", value)
74+
}
75+
bytesString := parts[1]
76+
multiple := parts[2]
77+
bytes, err := strconv.ParseFloat(bytesString, 64)
78+
if err != nil {
79+
return
80+
}
81+
82+
switch multiple {
83+
default:
84+
return int64(bytes), nil
85+
case "K", "KB":
86+
return int64(bytes * KB), nil
87+
case "M", "MB":
88+
return int64(bytes * MB), nil
89+
case "G", "GB":
90+
return int64(bytes * GB), nil
91+
case "T", "TB":
92+
return int64(bytes * TB), nil
93+
case "P", "PB":
94+
return int64(bytes * PB), nil
95+
case "E", "EB":
96+
return int64(bytes * EB), nil
97+
}
98+
}
99+
100+
// Format wraps global Bytes's Format function.
101+
func Format(b int64) string {
102+
return global.Format(b)
103+
}
104+
105+
// Parse wraps global Bytes's Parse function.
106+
func Parse(val string) (int64, error) {
107+
return global.Parse(val)
108+
}

demo/bytes/bytes_test.go

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
package bytes
2+
3+
import (
4+
"math"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestBytesFormat(t *testing.T) {
11+
// B
12+
b := Format(0)
13+
assert.Equal(t, "0", b)
14+
// B
15+
b = Format(515)
16+
assert.Equal(t, "515B", b)
17+
18+
// KB
19+
b = Format(31323)
20+
assert.Equal(t, "30.59KB", b)
21+
22+
// MB
23+
b = Format(13231323)
24+
assert.Equal(t, "12.62MB", b)
25+
26+
// GB
27+
b = Format(7323232398)
28+
assert.Equal(t, "6.82GB", b)
29+
30+
// TB
31+
b = Format(7323232398434)
32+
assert.Equal(t, "6.66TB", b)
33+
34+
// PB
35+
b = Format(9923232398434432)
36+
assert.Equal(t, "8.81PB", b)
37+
38+
// EB
39+
b = Format(math.MaxInt64)
40+
assert.Equal(t, "8.00EB", b)
41+
}
42+
43+
func TestBytesParseErrors(t *testing.T) {
44+
_, err := Parse("B999")
45+
if assert.Error(t, err) {
46+
assert.EqualError(t, err, "error parsing value=B999")
47+
}
48+
}
49+
50+
func TestFloats(t *testing.T) {
51+
// From string:
52+
str := "12.25KB"
53+
value, err := Parse(str)
54+
assert.NoError(t, err)
55+
assert.Equal(t, int64(12544), value)
56+
57+
str2 := Format(value)
58+
assert.Equal(t, str, str2)
59+
60+
// To string:
61+
val := int64(13233029)
62+
str = Format(val)
63+
assert.Equal(t, "12.62MB", str)
64+
65+
val2, err := Parse(str)
66+
assert.NoError(t, err)
67+
assert.Equal(t, val, val2)
68+
}
69+
70+
func TestBytesParse(t *testing.T) {
71+
// B
72+
b, err := Parse("999")
73+
if assert.NoError(t, err) {
74+
assert.Equal(t, int64(999), b)
75+
}
76+
b, err = Parse("-100")
77+
if assert.NoError(t, err) {
78+
assert.Equal(t, int64(-100), b)
79+
}
80+
b, err = Parse("100.1")
81+
if assert.NoError(t, err) {
82+
assert.Equal(t, int64(100), b)
83+
}
84+
b, err = Parse("515B")
85+
if assert.NoError(t, err) {
86+
assert.Equal(t, int64(515), b)
87+
}
88+
89+
// KB
90+
b, err = Parse("12.25KB")
91+
if assert.NoError(t, err) {
92+
assert.Equal(t, int64(12544), b)
93+
}
94+
b, err = Parse("12KB")
95+
if assert.NoError(t, err) {
96+
assert.Equal(t, int64(12288), b)
97+
}
98+
b, err = Parse("12K")
99+
if assert.NoError(t, err) {
100+
assert.Equal(t, int64(12288), b)
101+
}
102+
103+
// MB
104+
b, err = Parse("2MB")
105+
if assert.NoError(t, err) {
106+
assert.Equal(t, int64(2097152), b)
107+
}
108+
b, err = Parse("2M")
109+
if assert.NoError(t, err) {
110+
assert.Equal(t, int64(2097152), b)
111+
}
112+
113+
// GB
114+
b, err = Parse("6GB")
115+
if assert.NoError(t, err) {
116+
assert.Equal(t, int64(6442450944), b)
117+
}
118+
b, err = Parse("6G")
119+
if assert.NoError(t, err) {
120+
assert.Equal(t, int64(6442450944), b)
121+
}
122+
123+
// TB
124+
b, err = Parse("5TB")
125+
if assert.NoError(t, err) {
126+
assert.Equal(t, int64(5497558138880), b)
127+
}
128+
b, err = Parse("5T")
129+
if assert.NoError(t, err) {
130+
assert.Equal(t, int64(5497558138880), b)
131+
}
132+
133+
// PB
134+
b, err = Parse("9PB")
135+
if assert.NoError(t, err) {
136+
assert.Equal(t, int64(10133099161583616), b)
137+
}
138+
b, err = Parse("9P")
139+
if assert.NoError(t, err) {
140+
assert.Equal(t, int64(10133099161583616), b)
141+
}
142+
143+
// EB
144+
b, err = Parse("8EB")
145+
if assert.NoError(t, err) {
146+
assert.True(t, math.MaxInt64 == b-1)
147+
}
148+
b, err = Parse("8E")
149+
if assert.NoError(t, err) {
150+
assert.True(t, math.MaxInt64 == b-1)
151+
}
152+
}

0 commit comments

Comments
 (0)