1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-23 13:52:26 +08:00

Compare commits

...

11 Commits

Author SHA1 Message Date
dudaodong
3050d93703 release v2.2.2 2023-06-20 11:11:27 +08:00
dudaodong
efcfbfb6a1 fix: fix failed unit test 2023-06-20 11:10:33 +08:00
dudaodong
844b7a2c3b release v2.2.2 2023-06-20 10:59:12 +08:00
dudaodong
c8a536eafc doc: add doc for ZipAppendEntry 2023-06-17 19:54:09 +08:00
dudaodong
0fd268face Merge branch 'main' into v2 2023-06-17 19:38:53 +08:00
TheLastSunset
8ced7e887f feat: add ZipAppendEntry (#113) 2023-06-17 19:36:42 +08:00
dudaodong
957568ed5c doc: format code in doc file 2023-06-15 10:13:27 +08:00
dudaodong
fffabd0ffa Merge branch 'main' into v2 2023-06-13 13:58:29 +08:00
Mickls
e839af3ef9 feat: Add support for uploading files in SendRequest (#111) 2023-06-13 13:55:47 +08:00
dudaodong
1650e70d04 Merge branch 'main' into v2 2023-06-13 10:15:17 +08:00
Thijs Schreijer
23382b2b76 fix doc comment typo (#110) 2023-06-12 20:13:14 +08:00
23 changed files with 899 additions and 519 deletions

View File

@@ -4,7 +4,7 @@
<br/> <br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf) ![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.2.1-green.svg)](https://github.com/duke-git/lancet/releases) [![Release](https://img.shields.io/badge/release-2.2.2-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2) [![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2) [![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml) [![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -38,7 +38,7 @@ English | [简体中文](./README_zh-CN.md)
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
``` ```
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.3.9. </b> 2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.4.0. </b>
```go ```go
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
@@ -282,6 +282,10 @@ import "github.com/duke-git/lancet/v2/convertor"
- **<big>ToInterface</big>** : converts reflect value to its interface type. - **<big>ToInterface</big>** : converts reflect value to its interface type.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToInterface)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToInterface)]
[[play](https://go.dev/play/p/syqw0-WG7Xd)] [[play](https://go.dev/play/p/syqw0-WG7Xd)]
- **<big>Utf8ToGbk</big>** : converts utf8 encoding data to GBK encoding data
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#Utf8ToGbk)]
- **<big>GbkToUtf8</big>** : converts GBK encoding data to utf8 encoding data.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#GbkToUtf8)]
### 6. Cryptor package is for data encryption and decryption. ### 6. Cryptor package is for data encryption and decryption.
@@ -581,9 +585,11 @@ import "github.com/duke-git/lancet/v2/fileutil"
- **<big>ReadFileByLine</big>** : read file line by line, return string slice of file content. - **<big>ReadFileByLine</big>** : read file line by line, return string slice of file content.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadFileByLine)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadFileByLine)]
[[play](https://go.dev/play/p/svJP_7ZrBrD)] [[play](https://go.dev/play/p/svJP_7ZrBrD)]
- **<big>Zip</big>** : create zip file. - **<big>Zip</big>** : create a zip file of fpath, fpath could be a file or a directory.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#Zip)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#Zip)]
[[play](https://go.dev/play/p/j-3sWBp8ik_P)] [[play](https://go.dev/play/p/j-3sWBp8ik_P)]
- **<big>ZipAppendEntry</big>** : append a single file or directory by fpath to an existing zip file.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ZipAppendEntry)]
- **<big>UnZip</big>** : unzip the zip file and save it to dest path. - **<big>UnZip</big>** : unzip the zip file and save it to dest path.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#UnZip)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#UnZip)]
[[play](https://go.dev/play/p/g0w34kS7B8m)] [[play](https://go.dev/play/p/g0w34kS7B8m)]
@@ -605,6 +611,8 @@ import "github.com/duke-git/lancet/v2/fileutil"
- **<big>ReadCsvFile</big>** : read file content into slice. - **<big>ReadCsvFile</big>** : read file content into slice.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadCsvFile)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadCsvFile)]
[[play](https://go.dev/play/p/OExTkhGEd3_u)] [[play](https://go.dev/play/p/OExTkhGEd3_u)]
- **<big>WriteCsvFile</big>** : write content to target csv file.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#WriteCsvFile)]
- **<big>WriteBytesToFile</big>** : write bytes to target file. - **<big>WriteBytesToFile</big>** : write bytes to target file.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#WriteBytesToFile)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#WriteBytesToFile)]
[[play](https://go.dev/play/p/s7QlDxMj3P8)] [[play](https://go.dev/play/p/s7QlDxMj3P8)]
@@ -825,7 +833,10 @@ import "github.com/duke-git/lancet/v2/mathutil"
- **<big>Sin</big>** : return the sine of the radian argument. - **<big>Sin</big>** : return the sine of the radian argument.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Sin)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Sin)]
[[play](https://go.dev/play/p/TWMQlMywDsP)] [[play](https://go.dev/play/p/TWMQlMywDsP)]
- **<big>Log</big>** : returns the logarithm of base n.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Log)]
- **<big>Sum</big>** : return sum of passed numbers.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Sum)]
### 14. Netutil package contains functions to get net information and send http request. ### 14. Netutil package contains functions to get net information and send http request.
@@ -932,6 +943,8 @@ import "github.com/duke-git/lancet/v2/random"
- **<big>UUIdV4</big>** : generate a random UUID of version 4 according to RFC 4122. - **<big>UUIdV4</big>** : generate a random UUID of version 4 according to RFC 4122.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)]
[[play](https://go.dev/play/p/_Z9SFmr28ft)] [[play](https://go.dev/play/p/_Z9SFmr28ft)]
- **<big>RandUniqueIntSlice</big>** : generate a slice of random int of length n that do not repeat.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandUniqueIntSlice)]
### 16. Retry package is for executing a function repeatedly until it was successful or canceled by the context. ### 16. Retry package is for executing a function repeatedly until it was successful or canceled by the context.
@@ -1405,7 +1418,8 @@ import "github.com/duke-git/lancet/v2/strutil"
- **<big>HideString</big>** : Hide some chars in source string with param `replaceChar`. - **<big>HideString</big>** : Hide some chars in source string with param `replaceChar`.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#HideString)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#HideString)]
[[play](https://go.dev/play/p/pzbaIVCTreZ)] [[play](https://go.dev/play/p/pzbaIVCTreZ)]
- **<big>RemoveWhiteSpace</big>** : remove whitespace characters from a string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#RemoveWhiteSpace)]
### 21. System package contain some functions about os, runtime, shell command. ### 21. System package contain some functions about os, runtime, shell command.

View File

@@ -4,7 +4,7 @@
<br/> <br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf) ![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.2.1-green.svg)](https://github.com/duke-git/lancet/releases) [![Release](https://img.shields.io/badge/release-2.2.2-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2) [![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2) [![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml) [![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -25,7 +25,7 @@
- 👏 全面、高效、可复用。 - 👏 全面、高效、可复用。
- 💪 500+常用 go 工具函数,支持 string、slice、datetime、net、crypt... - 💪 500+常用 go 工具函数,支持 string、slice、datetime、net、crypt...
- 💅 只依赖 go 标准库和 golang.org/x。 - 💅 只依赖 go 标准库和 golang.org/x。
- 🌍 所有导出函数单元测试覆盖率100%。 - 🌍 所有导出函数单元测试覆盖率 100%。
## 安装 ## 安装
@@ -37,7 +37,7 @@
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
``` ```
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.3.9。</b> 2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.0。</b>
```go ```go
go get github.com/duke-git/lancet// 使用go1.18以下版本, 必须安装v1.x.x版本 go get github.com/duke-git/lancet// 使用go1.18以下版本, 必须安装v1.x.x版本
@@ -281,6 +281,10 @@ import "github.com/duke-git/lancet/v2/convertor"
- **<big>ToInterface</big>** : 将反射值转换成对应的 interface 类型。 - **<big>ToInterface</big>** : 将反射值转换成对应的 interface 类型。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToInterface)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToInterface)]
[[play](https://go.dev/play/p/syqw0-WG7Xd)] [[play](https://go.dev/play/p/syqw0-WG7Xd)]
- **<big>Utf8ToGbk</big>** : utf8 编码转 GBK 编码。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#Utf8ToGbk)]
- **<big>GbkToUtf8</big>** : GBK 编码转 utf8 编码。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#GbkToUtf8)]
### 6. cryptor 加密包支持数据加密和解密,获取 md5hash 值。支持 base64, md5, hmac, aes, des, rsa。 ### 6. cryptor 加密包支持数据加密和解密,获取 md5hash 值。支持 base64, md5, hmac, aes, des, rsa。
@@ -503,7 +507,6 @@ import "github.com/duke-git/lancet/v2/datetime"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#IsWeekend)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#IsWeekend)]
[[play](https://go.dev/play/p/cupRM5aZOIY)] [[play](https://go.dev/play/p/cupRM5aZOIY)]
### 8. datastructure 包含一些普通的数据结构实现。例如list, linklist, stack, queue, set, tree, graph. ### 8. datastructure 包含一些普通的数据结构实现。例如list, linklist, stack, queue, set, tree, graph.
```go ```go
@@ -586,6 +589,8 @@ import "github.com/duke-git/lancet/v2/fileutil"
- **<big>Zip</big>** : zip 压缩文件, 参数可以是文件或目录。 - **<big>Zip</big>** : zip 压缩文件, 参数可以是文件或目录。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#Zip)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#Zip)]
[[play](https://go.dev/play/p/j-3sWBp8ik_P)] [[play](https://go.dev/play/p/j-3sWBp8ik_P)]
- **<big>ZipAppendEntry</big>** : 通过将单个文件或目录追加到现有的 zip 文件。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ZipAppendEntry)]
- **<big>UnZip</big>** : zip 解压缩文件并保存在目录中。 - **<big>UnZip</big>** : zip 解压缩文件并保存在目录中。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#UnZip)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#UnZip)]
[[play](https://go.dev/play/p/g0w34kS7B8m)] [[play](https://go.dev/play/p/g0w34kS7B8m)]
@@ -607,15 +612,15 @@ import "github.com/duke-git/lancet/v2/fileutil"
- **<big>ReadCsvFile</big>** : 读取 csv 文件内容到切片。 - **<big>ReadCsvFile</big>** : 读取 csv 文件内容到切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ReadCsvFile)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ReadCsvFile)]
[[play](https://go.dev/play/p/OExTkhGEd3_u)] [[play](https://go.dev/play/p/OExTkhGEd3_u)]
- **<big>WriteBytesToFile</big>** : 将bytes写入文件 - **<big>WriteCsvFile</big>** : 向 csv 文件写入内容
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#WriteCsvFile)]
- **<big>WriteBytesToFile</big>** : 将 bytes 写入文件。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#WriteBytesToFile)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#WriteBytesToFile)]
[[play](https://go.dev/play/p/s7QlDxMj3P8)] [[play](https://go.dev/play/p/s7QlDxMj3P8)]
- **<big>WriteStringToFile</big>** : 将字符串写入文件。 - **<big>WriteStringToFile</big>** : 将字符串写入文件。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#WriteStringToFile)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#WriteStringToFile)]
[[play](https://go.dev/play/p/GhLS6d8lH_g)] [[play](https://go.dev/play/p/GhLS6d8lH_g)]
### 10. formatter 格式化器包含一些数据格式化处理方法。 ### 10. formatter 格式化器包含一些数据格式化处理方法。
```go ```go
@@ -828,7 +833,10 @@ import "github.com/duke-git/lancet/v2/mathutil"
- **<big>Sin</big>** : 计算弧度的正弦值。 - **<big>Sin</big>** : 计算弧度的正弦值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Sin)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Sin)]
[[play](https://go.dev/play/p/TWMQlMywDsP)] [[play](https://go.dev/play/p/TWMQlMywDsP)]
- **<big>Log</big>** : 计算以 base 为底 n 的对数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Log)]
- **<big>Sum</big>** : 求传入参数之和。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Sum)]
### 14. netutil 网络包支持获取 ip 地址,发送 http 请求。 ### 14. netutil 网络包支持获取 ip 地址,发送 http 请求。
@@ -935,6 +943,8 @@ import "github.com/duke-git/lancet/v2/random"
- **<big>UUIdV4</big>** : 生成 UUID v4 字符串。 - **<big>UUIdV4</big>** : 生成 UUID v4 字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#UUIdV4)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#UUIdV4)]
[[play](https://go.dev/play/p/_Z9SFmr28ft)] [[play](https://go.dev/play/p/_Z9SFmr28ft)]
- **<big>RandUniqueIntSlice</big>** : 生成一个不重复的长度为n的随机int切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandUniqueIntSlice)]
### 16. retry 重试执行函数直到函数运行成功或被 context cancel。 ### 16. retry 重试执行函数直到函数运行成功或被 context cancel。
@@ -1411,7 +1421,8 @@ import "github.com/duke-git/lancet/v2/strutil"
- **<big>HideString</big>** : 隐藏源字符串中的一些字符。 - **<big>HideString</big>** : 隐藏源字符串中的一些字符。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#HideString)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#HideString)]
[[play](https://go.dev/play/p/pzbaIVCTreZ)] [[play](https://go.dev/play/p/pzbaIVCTreZ)]
- **<big>RemoveWhiteSpace</big>** : 删除字符串中的空格。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#RemoveWhiteSpace)]
### 21. system 包含 os, runtime, shell command 的相关函数。 ### 21. system 包含 os, runtime, shell command 的相关函数。

View File

@@ -41,6 +41,8 @@ import (
- [DeepClone](#DeepClone) - [DeepClone](#DeepClone)
- [CopyProperties](#CopyProperties) - [CopyProperties](#CopyProperties)
- [ToInterface](#ToInterface) - [ToInterface](#ToInterface)
- [Utf8ToGbk](#Utf8ToGbk)
- [GbkToUtf8](#GbkToUtf8)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>

View File

@@ -37,6 +37,7 @@ import (
- [ReadFileToString](#ReadFileToString) - [ReadFileToString](#ReadFileToString)
- [ReadFileByLine](#ReadFileByLine) - [ReadFileByLine](#ReadFileByLine)
- [Zip](#Zip) - [Zip](#Zip)
- [ZipAppendEntry](#ZipAppendEntry)
- [UnZip](#UnZip) - [UnZip](#UnZip)
- [IsZipFile](#IsZipFile) - [IsZipFile](#IsZipFile)
- [FileSize](#FileSize) - [FileSize](#FileSize)
@@ -476,6 +477,34 @@ func main() {
} }
``` ```
### <span id="ZipAppendEntry">ZipAppendEntry</span>
<p>Append a single file or directory by fpath to an existing zip file.</p>
<b>Signature:</b>
```go
func ZipAppendEntry(fpath string, destPath string) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.ZipAppendEntry("./test.txt", "./test.zip")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="UnZip">UnZip</span> ### <span id="UnZip">UnZip</span>
<p>Unzip the file and save it to dest path.</p> <p>Unzip the file and save it to dest path.</p>

View File

@@ -37,6 +37,7 @@ import (
- [ReadFileToString](#ReadFileToString) - [ReadFileToString](#ReadFileToString)
- [ReadFileByLine](#ReadFileByLine) - [ReadFileByLine](#ReadFileByLine)
- [Zip](#Zip) - [Zip](#Zip)
- [ZipAppendEntry](#ZipAppendEntry)
- [UnZip](#UnZip) - [UnZip](#UnZip)
- [IsZipFile](#IsZipFile) - [IsZipFile](#IsZipFile)
- [FileSize](#FileSize) - [FileSize](#FileSize)
@@ -476,6 +477,34 @@ func main() {
} }
``` ```
### <span id="ZipAppendEntry">ZipAppendEntry</span>
<p>通过将单个文件或目录追加到现有的zip文件</p>
<b>函数签名:</b>
```go
func ZipAppendEntry(fpath string, destPath string) error
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.ZipAppendEntry("./test.txt", "./test.zip")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="UnZip">UnZip</span> ### <span id="UnZip">UnZip</span>
<p>zip解压缩文件并保存在目录中</p> <p>zip解压缩文件并保存在目录中</p>
@@ -701,7 +730,6 @@ func main() {
} }
``` ```
### <span id="WriteBytesToFile">WriteBytesToFile</span> ### <span id="WriteBytesToFile">WriteBytesToFile</span>
<p>将bytes写入文件。</p> <p>将bytes写入文件。</p>
@@ -751,7 +779,6 @@ func main() {
} }
``` ```
### <span id="WriteStringToFile">WriteStringToFile</span> ### <span id="WriteStringToFile">WriteStringToFile</span>
<p>将字符串写入文件。</p> <p>将字符串写入文件。</p>

View File

@@ -789,7 +789,6 @@ func main() {
} }
``` ```
### <span id="Cos">Cos</span> ### <span id="Cos">Cos</span>
<p>计算弧度的余弦值</p> <p>计算弧度的余弦值</p>
@@ -832,7 +831,6 @@ func main() {
} }
``` ```
### <span id="Sin">Sin</span> ### <span id="Sin">Sin</span>
<p>计算弧度的正弦值</p> <p>计算弧度的正弦值</p>

View File

@@ -21,6 +21,7 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Index: ## Index:
- [Tag](#Tag) - [Tag](#Tag)
- [Name](#Name) - [Name](#Name)
- [Value](#Value) - [Value](#Value)

View File

@@ -21,6 +21,7 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Index: ## Index:
- [New](#New) - [New](#New)
- [ToMap](#ToMap) - [ToMap](#ToMap)
- [Fields](#Fields) - [Fields](#Fields)

View File

@@ -21,6 +21,7 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 目录: ## 目录:
- [New](#New) - [New](#New)
- [ToMap](#ToMap) - [ToMap](#ToMap)
- [Fields](#Fields) - [Fields](#Fields)
@@ -70,7 +71,7 @@ func main() {
func (s *Struct) ToMap() (map[string]any, error) func (s *Struct) ToMap() (map[string]any, error)
``` ```
<b>除此之外提供一个便捷的静态方法ToMap</b> <b>除此之外,提供一个便捷的静态方法 ToMap</b>
```go ```go
func ToMap(v any) (map[string]any, error) func ToMap(v any) (map[string]any, error)

View File

@@ -1322,7 +1322,6 @@ func main() {
} }
``` ```
### <span id="ContainsAll">ContainsAll</span> ### <span id="ContainsAll">ContainsAll</span>
<p>Return true if target string contains all the substrings.</p> <p>Return true if target string contains all the substrings.</p>
@@ -1392,7 +1391,6 @@ func main() {
} }
``` ```
### <span id="RemoveWhiteSpace">RemoveWhiteSpace</span> ### <span id="RemoveWhiteSpace">RemoveWhiteSpace</span>
<p>Remove whitespace characters from a string. when set repalceAll is true removes all whitespace, false only replaces consecutive whitespace characters with one space.</p> <p>Remove whitespace characters from a string. when set repalceAll is true removes all whitespace, false only replaces consecutive whitespace characters with one space.</p>

View File

@@ -208,7 +208,11 @@ func Zip(fpath string, destPath string) error {
archive := zip.NewWriter(zipFile) archive := zip.NewWriter(zipFile)
defer archive.Close() defer archive.Close()
err = filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error { return addFileToArchive(fpath, archive)
}
func addFileToArchive(fpath string, archive *zip.Writer) error {
err := filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
} }
@@ -224,32 +228,22 @@ func Zip(fpath string, destPath string) error {
header.Name += "/" header.Name += "/"
} else { } else {
header.Method = zip.Deflate header.Method = zip.Deflate
}
writer, err := archive.CreateHeader(header) writer, err := archive.CreateHeader(header)
if err != nil { if err != nil {
return err return err
} }
if !info.IsDir() {
file, err := os.Open(path) file, err := os.Open(path)
if err != nil { if err != nil {
return err return err
} }
defer file.Close() defer file.Close()
_, err = io.Copy(writer, file) if _, err := io.Copy(writer, file); err != nil {
if err != nil {
return err return err
} }
} }
return nil return nil
}) })
if err != nil {
return err return err
}
return nil
} }
// UnZip unzip the file and save it to destPath. // UnZip unzip the file and save it to destPath.
@@ -302,6 +296,64 @@ func UnZip(zipFile string, destPath string) error {
return nil return nil
} }
// ZipAppendEntry append a single file or directory by fpath to an existing zip file.
// Play: https://go.dev/play/p/cxvaT8TRNQp
func ZipAppendEntry(fpath string, destPath string) error {
tempFile, err := os.CreateTemp("", "temp.zip")
if err != nil {
return err
}
defer os.Remove(tempFile.Name())
zipReader, err := zip.OpenReader(destPath)
if err != nil {
return err
}
archive := zip.NewWriter(tempFile)
for _, zipItem := range zipReader.File {
zipItemReader, err := zipItem.Open()
if err != nil {
return err
}
header, err := zip.FileInfoHeader(zipItem.FileInfo())
if err != nil {
return err
}
header.Name = zipItem.Name
targetItem, err := archive.CreateHeader(header)
if err != nil {
return err
}
_, err = io.Copy(targetItem, zipItemReader)
if err != nil {
return err
}
}
err = addFileToArchive(fpath, archive)
if err != nil {
return err
}
err = zipReader.Close()
if err != nil {
return err
}
err = archive.Close()
if err != nil {
return err
}
err = tempFile.Close()
if err != nil {
return err
}
return CopyFile(tempFile.Name(), destPath)
}
func safeFilepathJoin(path1, path2 string) (string, error) { func safeFilepathJoin(path1, path2 string) (string, error) {
relPath, err := filepath.Rel(".", path2) relPath, err := filepath.Rel(".", path2)
if err != nil || strings.HasPrefix(relPath, "..") { if err != nil || strings.HasPrefix(relPath, "..") {
@@ -402,7 +454,7 @@ func MTime(filepath string) (int64, error) {
return f.ModTime().Unix(), nil return f.ModTime().Unix(), nil
} }
// MTime returns file sha value, param `shaType` should be 1, 256 or 512. // Sha returns file sha value, param `shaType` should be 1, 256 or 512.
// Play: https://go.dev/play/p/VfEEcO2MJYf // Play: https://go.dev/play/p/VfEEcO2MJYf
func Sha(filepath string, shaType ...int) (string, error) { func Sha(filepath string, shaType ...int) (string, error) {
file, err := os.Open(filepath) file, err := os.Open(filepath)

View File

@@ -175,11 +175,11 @@ func ExampleReadFileByLine() {
} }
func ExampleListFileNames() { func ExampleListFileNames() {
fileList, _ := ListFileNames("./") fileList, _ := ListFileNames("../internal")
fmt.Println(fileList) fmt.Println(fileList)
// Output: // Output:
// [file.go file_example_test.go file_test.go] // [assert.go assert_test.go error_join.go]
} }
func ExampleZip() { func ExampleZip() {
@@ -224,6 +224,28 @@ func ExampleUnZip() {
// application/octet-stream // application/octet-stream
} }
func ExampleZipAppendEntry() {
zipFile := "./test.zip"
CopyFile("./testdata/file.go.zip", zipFile)
ZipAppendEntry("./testdata", zipFile)
unZipPath := "./unzip"
UnZip(zipFile, unZipPath)
fmt.Println(IsExist("./unzip/file.go"))
fmt.Println(IsExist("./unzip/testdata/file.go.zip"))
fmt.Println(IsExist("./unzip/testdata/test.txt"))
os.Remove(zipFile)
os.RemoveAll(unZipPath)
// Output:
// true
// true
// true
}
func ExampleIsZipFile() { func ExampleIsZipFile() {
result1 := IsZipFile("./file.go") result1 := IsZipFile("./file.go")
result2 := IsZipFile("./testdata/file.go.zip") result2 := IsZipFile("./testdata/file.go.zip")

View File

@@ -191,6 +191,44 @@ func TestZipAndUnZip(t *testing.T) {
os.RemoveAll(unZipPath) os.RemoveAll(unZipPath)
} }
func TestZipAppendEntry(t *testing.T) {
assert := internal.NewAssert(t, "TestZipAppendEntry")
zipFile := "./text.zip"
err := CopyFile("./testdata/file.go.zip", zipFile)
assert.IsNil(err)
srcFile := "./text.txt"
CreateFile(srcFile)
file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, os.ModePerm)
_, err = file.WriteString("hello\nworld")
if err != nil {
t.Fail()
}
file.Close()
err = ZipAppendEntry(srcFile, zipFile)
assert.IsNil(err)
err = ZipAppendEntry("./testdata", zipFile)
assert.IsNil(err)
unZipPath := "./unzip"
err = UnZip(zipFile, unZipPath)
assert.IsNil(err)
assert.Equal(true, IsExist("./unzip/text.txt"))
assert.Equal(true, IsExist("./unzip/file.go"))
assert.Equal(true, IsExist("./unzip/testdata/file.go.zip"))
assert.Equal(true, IsExist("./unzip/testdata/test.txt"))
os.Remove(srcFile)
os.Remove(zipFile)
os.RemoveAll(unZipPath)
}
func TestFileMode(t *testing.T) { func TestFileMode(t *testing.T) {
assert := internal.NewAssert(t, "TestFileMode") assert := internal.NewAssert(t, "TestFileMode")
@@ -235,10 +273,10 @@ func TestMiMeType(t *testing.T) {
func TestListFileNames(t *testing.T) { func TestListFileNames(t *testing.T) {
assert := internal.NewAssert(t, "TestListFileNames") assert := internal.NewAssert(t, "TestListFileNames")
filesInPath, err := ListFileNames("./") filesInPath, err := ListFileNames("../internal")
assert.IsNil(err) assert.IsNil(err)
expected := []string{"file.go", "file_example_test.go", "file_test.go"} expected := []string{"assert.go", "assert_test.go", "error_join.go"}
assert.Equal(expected, filesInPath) assert.Equal(expected, filesInPath)
} }

View File

@@ -19,8 +19,10 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"mime/multipart"
"net/http" "net/http"
"net/url" "net/url"
"os"
"sort" "sort"
"strings" "strings"
"time" "time"
@@ -94,6 +96,7 @@ type HttpRequest struct {
Headers http.Header Headers http.Header
QueryParams url.Values QueryParams url.Values
FormData url.Values FormData url.Values
File *File
Body []byte Body []byte
} }
@@ -186,7 +189,11 @@ func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, err
} }
if request.FormData != nil { if request.FormData != nil {
client.setFormData(req, request.FormData) if request.File != nil {
err = client.setFormData(req, request.FormData, setFile(request.File))
} else {
err = client.setFormData(req, request.FormData, nil)
}
} }
client.Request = req client.Request = req
@@ -251,10 +258,80 @@ func (client *HttpClient) setQueryParam(req *http.Request, reqUrl string, queryP
return nil return nil
} }
func (client *HttpClient) setFormData(req *http.Request, values url.Values) { // setFormData set http request FormData param
func (client *HttpClient) setFormData(req *http.Request, values url.Values, setFile SetFileFunc) error {
if setFile != nil {
err := setFile(req, values)
if err != nil {
return err
}
} else {
formData := []byte(values.Encode()) formData := []byte(values.Encode())
req.Body = io.NopCloser(bytes.NewReader(formData)) req.Body = io.NopCloser(bytes.NewReader(formData))
req.ContentLength = int64(len(formData)) req.ContentLength = int64(len(formData))
}
return nil
}
type SetFileFunc func(req *http.Request, values url.Values) error
// File struct is a combination of file attributes
type File struct {
Content []byte
Path string
FieldName string
FileName string
}
// setFile set parameters for http request formdata file upload
func setFile(f *File) SetFileFunc {
return func(req *http.Request, values url.Values) error {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
for key, vals := range values {
for _, val := range vals {
err := writer.WriteField(key, val)
if err != nil {
return err
}
}
}
if f.Content != nil {
part, err := writer.CreateFormFile(f.FieldName, f.FileName)
if err != nil {
return err
}
part.Write(f.Content)
} else if f.Path != "" {
file, err := os.Open(f.Path)
if err != nil {
return err
}
defer file.Close()
part, err := writer.CreateFormFile(f.FieldName, f.FileName)
if err != nil {
return err
}
_, err = io.Copy(part, file)
if err != nil {
return err
}
}
err := writer.Close()
if err != nil {
return err
}
req.Body = io.NopCloser(body)
req.Header.Set("Content-Type", writer.FormDataContentType())
req.ContentLength = int64(body.Len())
return nil
}
} }
// validateRequest check if a request has url, and valid method. // validateRequest check if a request has url, and valid method.

View File

@@ -1,11 +1,15 @@
package netutil package netutil
import ( import (
"bytes"
"encoding/json" "encoding/json"
"io" "io"
"io/ioutil"
"log" "log"
"net/http" "net/http"
"net/http/httptest"
"net/url" "net/url"
"os"
"testing" "testing"
"github.com/duke-git/lancet/v2/internal" "github.com/duke-git/lancet/v2/internal"
@@ -245,3 +249,108 @@ func TestStructToUrlValues(t *testing.T) {
assert.Equal("456", queryValues2.Get("userId")) assert.Equal("456", queryValues2.Get("userId"))
assert.Equal("", queryValues2.Get("name")) assert.Equal("", queryValues2.Get("name"))
} }
func handleFileRequest(t *testing.T, w http.ResponseWriter, r *http.Request) {
err := r.ParseMultipartForm(1024)
if err != nil {
t.Fatal(err)
}
key1 := r.FormValue("key1")
expectedKey1 := "value1"
if key1 != expectedKey1 {
t.Fatalf("expected %s, got %s", expectedKey1, key1)
}
key2 := r.FormValue("key2")
expectedKey2 := "value2"
if key2 != expectedKey2 {
t.Fatalf("expected %s, got %s", expectedKey2, key2)
}
file, header, err := r.FormFile("image")
if err != nil {
t.Fatal(err)
}
expectedFileName := "testImage.jpg"
if header.Filename != expectedFileName {
t.Fatalf("expected %s, got %s", expectedFileName, header.Filename)
}
defer file.Close()
content, err := ioutil.ReadAll(file)
if err != nil {
t.Fatal(err)
}
expectedContent := []byte("file content")
if !bytes.Equal(content, expectedContent) {
t.Fatalf("expected %s, got %s", string(expectedContent), string(content))
}
}
func TestSendRequestWithFileContent(t *testing.T) {
handler := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
handleFileRequest(t, writer, request)
})
server := httptest.NewServer(handler)
defer server.Close()
client := NewHttpClient()
request := &HttpRequest{
RawURL: server.URL,
Method: "POST",
File: &File{Content: []byte("file content"), FieldName: "image", FileName: "testImage.jpg"},
FormData: url.Values{"key1": {"value1"}, "key2": {"value2"}},
}
resp, err := client.SendRequest(request)
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Fatalf("expected %d, got %d", http.StatusOK, resp.StatusCode)
}
}
func TestSendRequestWithFilePath(t *testing.T) {
handler := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
handleFileRequest(t, writer, request)
})
server := httptest.NewServer(handler)
defer server.Close()
tmpFile, err := ioutil.TempFile("", "testImage.jpg")
if err != nil {
t.Fatal(err)
}
defer os.Remove(tmpFile.Name())
tmpFile.Write([]byte("file content"))
tmpFile.Close()
client := NewHttpClient()
request := &HttpRequest{
RawURL: server.URL,
Method: "POST",
File: &File{Path: tmpFile.Name(), FieldName: "image", FileName: "testImage.jpg"},
FormData: url.Values{"key1": {"value1"}, "key2": {"value2"}},
}
resp, err := client.SendRequest(request)
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Fatalf("expected %d, got %d", http.StatusOK, resp.StatusCode)
}
}