diff --git a/docs/api/packages/fileutil.md b/docs/api/packages/fileutil.md
index 4caa5e5..a5183d4 100644
--- a/docs/api/packages/fileutil.md
+++ b/docs/api/packages/fileutil.md
@@ -750,6 +750,10 @@ func main() {
函数签名:
```go
+// filepath: CSV文件路径。
+// records: 写入文件的map切片。map值必须为基本类型。会以map键的字母顺序写入。
+// appendToExistingFile: 是否为追加写模式。
+// delimiter: CSV文件分割符。
func WriteMapsToCsv(filepath string, records []map[string]string, append_to_existing_file bool, delimiter ...rune) error
```
@@ -770,23 +774,23 @@ func main() {
f, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
- records := []map[string]string{
- {"Name": "Lili", "Age": "22", "gender": "female"},
- {"Name": "Jim", "Age": "21", "gender": "male"},
+ records := []map[string]any{
+ {"Name": "Lili", "Age": "22", "Gender": "female"},
+ {"Name": "Jim", "Age": "21", "Gender": "male"},
}
- err := WriteMapsToCsv(csvFilePath, records, false, ';')
+ err := fileutil.WriteMapsToCsv(csvFilePath, records, false, ';')
if err != nil {
log.Fatal(err)
}
- content, err := ReadCsvFile(csvFilePath, ';')
+ content, err := fileutil.ReadCsvFile(csvFilePath, ';')
fmt.Println(content)
// Output:
- // [[Name Age gender] [Lili 22 female] [Jim 21 male]]
+ // [[Age Gender Name] [22 female Lili] [21 male Jim]]
}
```
diff --git a/docs/en/api/packages/fileutil.md b/docs/en/api/packages/fileutil.md
index c2c506a..a46be12 100644
--- a/docs/en/api/packages/fileutil.md
+++ b/docs/en/api/packages/fileutil.md
@@ -751,6 +751,10 @@ func main() {
Signature:
```go
+// filepath: path of the CSV file.
+// records: slice of maps to be written. the value of map should be basic type. The maps will be sorted by key in alphabeta order, then be written into csv file.
+// appendToExistingFile: If true, data will be appended to the file if it exists.
+// delimiter: Delimiter to use in the CSV file.
func WriteMapsToCsv(filepath string, records []map[string]string, append_to_existing_file bool, delimiter ...rune) error
```
@@ -771,23 +775,23 @@ func main() {
f, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
- records := []map[string]string{
- {"Name": "Lili", "Age": "22", "gender": "female"},
- {"Name": "Jim", "Age": "21", "gender": "male"},
+ records := []map[string]any{
+ {"Name": "Lili", "Age": "22", "Gender": "female"},
+ {"Name": "Jim", "Age": "21", "Gender": "male"},
}
- err := WriteMapsToCsv(csvFilePath, records, false, ';')
+ err := fileutil.WriteMapsToCsv(csvFilePath, records, false, ';')
if err != nil {
log.Fatal(err)
}
- content, err := ReadCsvFile(csvFilePath, ';')
+ content, err := fileutil.ReadCsvFile(csvFilePath, ';')
fmt.Println(content)
// Output:
- // [[Name Age gender] [Lili 22 female] [Jim 21 male]]
+ // [[Age Gender Name] [22 female Lili] [21 male Jim]]
}
```
diff --git a/fileutil/file.go b/fileutil/file.go
index d8c428e..a29a2a2 100644
--- a/fileutil/file.go
+++ b/fileutil/file.go
@@ -20,6 +20,7 @@ import (
"os"
"path/filepath"
"runtime"
+ "sort"
"strings"
"github.com/duke-git/lancet/v2/validator"
@@ -754,8 +755,22 @@ func escapeCSVField(field string, delimiter rune) string {
// WriteMapsToCsv write slice of map to csv file.
// Play: todo
-func WriteMapsToCsv(filepath string, records []map[string]string, append_to_existing_file bool, delimiter ...rune) error {
- var datas_to_write [][]string
+// filepath: Path to the CSV file.
+// records: Slice of maps to be written. the value of map should be basic type.
+// the maps will be sorted by key in alphabeta order, then be written into csv file.
+// appendToExistingFile: If true, data will be appended to the file if it exists.
+// delimiter: Delimiter to use in the CSV file.
+func WriteMapsToCsv(filepath string, records []map[string]any, appendToExistingFile bool, delimiter ...rune) error {
+ for _, record := range records {
+ for _, value := range record {
+ if !isCsvSupportedType(value) {
+ return errors.New("unsupported value type detected; only basic types are supported: \nbool, rune, string, int, int64, float32, float64, uint, byte, complex128, complex64, uintptr")
+ }
+ }
+ }
+
+ var datasToWrite [][]string
+
// 标题(列名)
var headers []string
if len(records) > 0 {
@@ -763,24 +778,44 @@ func WriteMapsToCsv(filepath string, records []map[string]string, append_to_exis
headers = append(headers, key)
}
}
+
+ // sort keys in alphabeta order
+ sort.Strings(headers)
+
// 追加模式不重复写字段名
- if !append_to_existing_file {
- datas_to_write = append(datas_to_write, headers)
+ if !appendToExistingFile {
+ datasToWrite = append(datasToWrite, headers)
}
- // 写入数据行
+
for _, record := range records {
var row []string
for _, header := range headers {
- row = append(row, record[header])
+ row = append(row, fmt.Sprintf("%v", record[header]))
}
- datas_to_write = append(datas_to_write, row)
+ datasToWrite = append(datasToWrite, row)
}
- // 提取自定义分隔符
+
var sep rune
if len(delimiter) > 0 {
sep = delimiter[0]
} else {
sep = ','
}
- return WriteCsvFile(filepath, datas_to_write, append_to_existing_file, sep)
+
+ return WriteCsvFile(filepath, datasToWrite, appendToExistingFile, sep)
}
+
+// check if the value of map which to be written into csv is basic type.
+func isCsvSupportedType(v interface{}) bool {
+ switch v.(type) {
+ case bool, rune, string, int, int64, float32, float64, uint, byte, complex128, complex64, uintptr:
+ return true
+ default:
+ return false
+ }
+}
+
+// sort map by key in alphabeta order.
+// func sortMap(records []map[string]any) []map[string]any {
+
+// }
diff --git a/fileutil/file_example_test.go b/fileutil/file_example_test.go
index b48d394..1932831 100644
--- a/fileutil/file_example_test.go
+++ b/fileutil/file_example_test.go
@@ -3,6 +3,7 @@ package fileutil
import (
"fmt"
"io"
+ "log"
"os"
)
@@ -331,26 +332,26 @@ func ExampleWriteCsvFile() {
// [[Lili 22 female] [Jim 21 male]]
}
-// func ExampleWriteMapsToCsv() {
-// csvFilePath := "./testdata/test3.csv"
-// records := []map[string]string{
-// {"Name": "Lili", "Age": "22", "gender": "female"},
-// {"Name": "Jim", "Age": "21", "gender": "male"},
-// }
+func ExampleWriteMapsToCsv() {
+ csvFilePath := "./testdata/test3.csv"
+ records := []map[string]any{
+ {"Name": "Lili", "Age": "22", "Gender": "female"},
+ {"Name": "Jim", "Age": "21", "Gender": "male"},
+ }
-// err := WriteMapsToCsv(csvFilePath, records, false, ';')
+ err := WriteMapsToCsv(csvFilePath, records, false, ';')
-// if err != nil {
-// log.Fatal(err)
-// }
+ if err != nil {
+ log.Fatal(err)
+ }
-// content, err := ReadCsvFile(csvFilePath, ';')
+ content, err := ReadCsvFile(csvFilePath, ';')
-// fmt.Println(content) //顺序不固定
+ fmt.Println(content)
-// // Output:
-// // [[Name Age gender] [Lili 22 female] [Jim 21 male]]
-// }
+ // Output:
+ // [[Age Gender Name] [22 female Lili] [21 male Jim]]
+}
func ExampleWriteStringToFile() {
filepath := "./test.txt"
diff --git a/fileutil/file_test.go b/fileutil/file_test.go
index 0a00c56..5750670 100644
--- a/fileutil/file_test.go
+++ b/fileutil/file_test.go
@@ -392,9 +392,9 @@ func TestWriteMapsToCsv(t *testing.T) {
assert := internal.NewAssert(t, "TestWriteMapsToCSV")
csvFilePath := "./testdata/test4.csv"
- records := []map[string]string{
- {"Name": "Lili", "Age": "22", "gender": "female"},
- {"Name": "Jim", "Age": "21", "gender": "male"},
+ records := []map[string]any{
+ {"Name": "Lili", "Age": "22", "Gender": "female"},
+ {"Name": "Jim", "Age": "21", "Gender": "male"},
}
err := WriteMapsToCsv(csvFilePath, records, false, ';')
@@ -407,7 +407,9 @@ func TestWriteMapsToCsv(t *testing.T) {
assert.Equal(3, len(content))
assert.Equal(3, len(content[0]))
- // assert.Equal("Lili", content[1][0])
+ assert.Equal("22", content[1][0])
+ assert.Equal("female", content[1][1])
+ assert.Equal("Lili", content[1][2])
}
func TestWriteStringToFile(t *testing.T) {
diff --git a/fileutil/testdata/test3.csv b/fileutil/testdata/test3.csv
index 965779c..aab46b6 100644
--- a/fileutil/testdata/test3.csv
+++ b/fileutil/testdata/test3.csv
@@ -1,3 +1,3 @@
-Age;gender;Name
+Age;Gender;Name
22;female;Lili
21;male;Jim
diff --git a/fileutil/testdata/test4.csv b/fileutil/testdata/test4.csv
index 875d813..aab46b6 100644
--- a/fileutil/testdata/test4.csv
+++ b/fileutil/testdata/test4.csv
@@ -1,3 +1,3 @@
-Name;Age;gender
-Lili;22;female
-Jim;21;male
+Age;Gender;Name
+22;female;Lili
+21;male;Jim