Skip to content

博客

Use Go Embed

Go1.16引入新的//go:embed指令,可以在编译时嵌入文件和目录,并对其进行访问。通过它,真正做到部署时只有一个二进制文件。

背景:2021-02-16,Go Team正式发布了Go1.16。该版本包含下面的一些重要变化:

  • embed 包和 //go:embed 指令
  • 增加对 macOS ARM64 的支持
  • 默认启用 Module
  • io/fs 包
  • 弃用io/ioutil

最后,还有许多其他改进和错误修复,包括构建速度提高了 20-25%,linux/amd64上内存使用量减少了 5-15%。有关更改的完整列表以及有关上述改进的更多信息,请参阅 Go 1.16 发行说明

基本思路是,在代码中添加特殊注释,Go将知道其包含的一个或多个文件。

Go源文件在引入“embed”包后,可以使用//go:embed指令在编译时,从包目录或者子目录的文件读取内容来初始化

string,[]byte,FS类型的变量。如,可以用下面的三种方式嵌入名为hello.txt文件,然后在运行时打印其内容。

目录结构:

Terminal window
.
├── main.go
└── hello.txt
  • 将文件内容嵌入到一个字符串变量
import (
_ "embed"
"fmt"
)
//go:embed hello.txt
var s string
fmt.Print(s)
  • 将文件内容嵌入到[]byte
import (
_ "embed"
"fmt"
)
//go:embed hello.txt
var b []byte
fmt.Print(string(b))
  • 将一个或多个文件嵌入到文件系统中
import (
_ "embed"
"fmt"
)
//go:embed hello.txt
var f embed.FS
data, _ := f.ReadFile("hello.txt")
fmt.Print(string(data))
package main
import (
_ "embed"
"fmt"
"strings"
)
var (
Version string = strings.TrimSpace(version)
//go:embed version.txt
version string
)
func main() {
fmt.Printf("Version %q\n", Version)
}

对于更复杂的示例,我们甚至可以根据是否将某个构建标记传递给go工具来有条件地包含版本信息。

version_dev.go
// +build !prod
package main
var version string = "dev"
version_prod.go
// +build prod
package main
import (
_ "embed"
)
//go:embed version.txt
var version string
Terminal window
$ go run .
Version "dev"
$ go run -tags prod .
Version "0.0.1"
package main
import (
_ "embed"
"fmt"
)
//go:embed quine.go
var src string
func main() {
fmt.Print(src)
}

当运行时,就可以将自己打印出来。

可以网站所需要的所有静态文件或者模板包含在一个可执行文件中,甚至可以通过命令行参数,在读取磁盘文件和读取嵌入文件之间进行切换。

package main
import (
"embed"
"io/fs"
"log"
"net/http"
"os"
)
func main() {
useOS := len(os.Args) > 1 && os.Args[1] == "live"
http.Handle("/", http.FileServer(getFileSystem(useOS)))
http.ListenAndServe(":8888", nil)
}
//go:embed static
var embededFiles embed.FS
func getFileSystem(useOS bool) http.FileSystem {
if useOS {
log.Print("using live mode")
return http.FS(os.DirFS("static"))
}
log.Print("using embed mode")
fsys, err := fs.Sub(embededFiles, "static")
if err != nil {
panic(err)
}
return http.FS(fsys)
}

关于嵌入有些地方需要注意,首先必须要将包导入到任何使用embed命令的文件中。如没有导入包时:

package main
import (
"fmt"
)
//go:embed file.txt
var s string
func main() {
fmt.Print(s)
}
$ go run mian.go
main.go:7:3: //go:embed only allowed in Go files that import "embed"

其次,embed命令只能在包级别变量使用,不能用在函数或方法中。

更多:使用规则,详见文档:https://golang.org/pkg/embed/

相关代码在https://github.com/bytedaring/embed

  1. Go 1.16 Release Notes
  2. embed Doc
  3. How to Use //go:embed
  4. Managing Go installations
  5. 来了来了!Go1.16 重磅发布

区分换行符

CRLF, LF 是用来表示文本换行的方式。CR(Carriage Return) 代表回车,对应字符 '\r';LF(Line Feed) 代表换行,对应字符 '\n'。不同的操作系统文本使用的换行符各不相同。

Windows 系统使用的是 CRLF, Unix系统(包括Linux, MacOS近些年的版本) 使用的是LF。

那么如何在命令行中,显示区分到底使用的是那个换行符,是CRLF,还是LF?可以使用下面几种工具:

  • less
  • cat
  • file

通过命令 file -k demo.txt .

  • 对于DOS/Windows 换行符, 会输出: with CRLF line terminators

  • 对于MAC换行符,会输出:with LF line endings

  • 对于Linux/Unix ”CR“, 则只会输出 text

cat -e 将Linux/Unix 换行符(\n 或 LF) 显示成 $, Dos/Windows换行符(\r\n 或者 CRLF)显示成 ^M$, 如:

Terminal window
--CRLF
$ cat -e 2020654103_2020-12-18.csv
LQH2HPN4R7MDRL,63036NC00-015-G,EY00875,2020654103,12000,12000^M$
DLW21HN900SQ2L,720400201-015-H,EY00H61,2020653533,300000,300000^M$
DLW21HN181SQ2L,720402M00-015-H,IZ00091,2020653533,18000,18000^M$
#LF
$ cat -e 2020654103_2020.csv
DLW21HN181SQ2L,720402M00-015-H,IZ00091,2020653533,18000,18000$
DLW21HN670HQ2L,720406000-015-H,IZ00339,2020653533,60000,60000$
DLW21HN670HQ2L,720406000-015-H,IZ00408,2020653533,24000,24000$

通过less -u 命令可以将 CR 显示成 ^M

man less:

Terminal window
-u or --underline-special
Causes backspaces and carriage returns to be treated as print-
able characters; that is, they are sent to the terminal when
they appear in the input.

将DOS换行符转换成Unix换行符(NeoVim/Vim)

Section titled “将DOS换行符转换成Unix换行符(NeoVim/Vim)”
  • dos2unix 是一个实用命令行工具,可以完成这个操作
  • set ff=unix 或者 set fileformat=unix 进行命令修改
  • :%s/\r//g

Docker搭建FTP服务器

使用Docker搭建FTP服务。使用的镜像是fauria/vsftpd

Terminal window
docker pull fauria/vsftpd
Terminal window
docker run -d --name vsftpd -v ~/sftp:/home/vsftpd \
-p 21:21 -p 20:20 -p 21100-21110:21100-21110 \
-e FTP_USER=myuser -e FTP_PASS=mypass \
-e PASV_ADDRESS=127.0.0.1 \
--restart=always \
fauria/vsftpd
#-p 进行端口绑定映射
#-v 添加容器数据卷
#-e FTP_USER=davion -e FTP_PASS=davion 添加一个初始化用户davion
#PASV_MIN_PORT和PASV_MAX_PORT映射的是被动模式下端口使用范围
#-name vsftpd 为容器命名为vsftpd
#--restart=always fauria/vsftpd docker 异常退出时自动重启容器

3. 在镜像中新增自定义的新用户

Section titled “3. 在镜像中新增自定义的新用户”
Terminal window
# 进入容器
docker exec -it vsftpd bash
# 创建
mkdir /home/vsftpd/myuser
echo -e "myuser\nmypass" >> /etc/vsftpd/virtual_users.txt
/usr/bin/db_load -T -t hash -f /etc/vsftpd/virtual_users.txt /etc/vsftpd/virtual_users.db
exit
#重启
docker restart vsftpd

在浏览器(或者其他ftp客户端工具)中输入:ftp://127.0.0.1 , 测试是否访问正常

@Bean和@Component

@Component and @Bean do two quite different things, and shouldn’t be confused.

@Component (and @Service and @Repository) are used to auto-detect and auto-configure beans using classpath scanning. There’s an implicit one-to-one mapping between the annotated class and the bean (i.e. one bean per class). Control of wiring is quite limited with this approach, since it’s purely declarative.

@Bean is used to explicitly declare a single bean, rather than letting Spring do it automatically as above. It decouples the declaration of the bean from the class definition, and lets you create and configure beans exactly how you choose.

@COMPONENT If we mark a class with @Component or one of the other Stereotype annotations these classes will be auto-detected using classpath scanning. As long as these classes are in under our base package or Spring is aware of another package to scan, a new bean will be created for each of these classes.

@BEAN @Bean is used to explicitly declare a single bean, rather than letting Spring do it automatically like we did with @Controller. It decouples the declaration of the bean from the class definition and lets you create and configure beans exactly how you choose.

@Component (@Controller @Service @Respository)作用于类上,只有在我们的SpringBoot应用程序启用了组件扫描并且包含了被注解的类时才有效。通过组件扫描,Spring将扫描整个类路径,并将所有@Component注释类添加到Spring Context,这里有的不足就是会把整个类当成bean注册到spring 容器上,如果这个类中并不是所有方法都需要注册为bean的话,会出现不需要的方法都注册成为bean,这时候必须确保这些不需要的方法也能注册为bean或者在扫描中加filter 过滤这些不需要的bean,否者spring将无法成功启动。

@Bean相对来说就更加灵活了,它可以独立加在方法上,按需注册到spring容器,而且如果你要用到第三方类库里面某个方法的时候,你就只能用@Bean把这个方法注册到spring容器,因为用@Component你需要配置组件扫描到这个第三方类路径而且还要在别人源代码加上这个注解,很明显是不现实的。

Mysqldump

抄录自https://www.cnblogs.com/flagsky/p/9762726.html

一、导出

1.1 导出表结构及数据

mysqldump -uroot -p --set-gtid-purged=OFF database table1 table2 > mysqldump.sql

1.2 只导出表结构

mysqldump -uroot -p --set-gtid-purged=OFF -d database table1 table2 > mysqldump.sql

1.3 只导出数据

mysqldump -uroot -p --set-gtid-purged=OFF -t database table1 table2 > mysqldump.sql

1.4 导出单张表

(1)导出表结构及数据(有where条件)

mysqldump -uroot -p --set-gtid-purged=OFF database table --where "限制条件" > mysqldump.sql
(2)只导出数据(有where条件)
mysqldump -uroot -p --set-gtid-purged=OFF --no-create-info database table --where "限制条件" > mysqldump.sql

参数说明: -d参数:等价于-–no-data,含义是不导出任何数据,只导出数据库表结构; -t参数:等价于—no-create-info,含义是只导出数据,而不添加CREATE TABLE语句;

2、导出数据库

2.1 导出所有数据库

mysqldump -uroot -p --all-databases > mysqldump.sql

2.2 导出单个数据库

mysqldump -uroot -p --databases db1 > mysqldump.sql

2.3 导出多个数据库

mysqldump -uroot -p --databases db1 db2 > mysqldump.sql

二、导入

1、导入表

mysql -uroot -p database < mysqldump.sql

2、导入数据库

mysql -uroot -p < mysqldump.sql

三、mysqldump常用参数说明

1、—all-databases , -A

含义:导出全部数据库。 示例:

Terminal window
mysqldump -uroot -p --all-databases

2、—all-tablespaces , -Y

含义:导出全部表空间。 示例:

Terminal window
mysqldump -uroot -p --all-databases --all-tablespaces

3、—no-tablespaces , -y

含义:不导出任何表空间信息。 示例:

Terminal window
mysqldump -uroot -p --all-databases --no-tablespaces

4、—add-drop-database

含义:每个数据库创建之前添加drop数据库语句。 示例:

Terminal window
mysqldump -uroot -p --all-databases --add-drop-database

5、—add-drop-table

含义:每个数据表创建之前添加drop数据表语句。(默认为打开状态,使用—skip-add-drop-table取消选项) 示例:

Terminal window
mysqldump -uroot -p --all-databases (默认添加drop语句)
mysqldump -uroot -p --all-databases –skip-add-drop-table (取消drop语句)

6、—add-locks

含义:在每个表导出之前增加LOCK TABLES并且之后UNLOCK TABLE。(默认为打开状态,使用—skip-add-locks取消选项) 示例:

Terminal window
mysqldump -uroot -p --all-databases (默认添加LOCK语句)
mysqldump -uroot -p --all-databases –skip-add-locks (取消LOCK语句)

7、—create-options, -a

含义:在CREATE TABLE语句中包括所有MySQL特性选项。(默认为打开状态) 示例:

Terminal window
mysqldump -uroot -p --all-databases

8、—databases, -B

含义:导出几个数据库。参数后面所有名字参量都被看作数据库名。 示例:

Terminal window
mysqldump -uroot -p --databases test mysql

9、—default-character-set

含义:设置默认字符集,默认值为utf8 示例:

Terminal window
mysqldump -uroot -p --all-databases --default-character-set=utf8

10、—events, -E

含义:导出事件。 示例:

Terminal window
mysqldump -uroot -p --all-databases --events

11、—flush-logs

含义:开始导出之前刷新日志。请注意:假如一次导出多个数据库(使用选项—databases或者—all-databases),将会逐个数据库刷新日志。除使用—lock-all-tables或者—master-data外。在这种情况下,日志将会被刷新一次,相应的所以表同时被锁定。因此,如果打算同时导出和刷新日志应该使用—lock-all-tables 或者—master-data 和—flush-logs。 示例:

Terminal window
mysqldump -uroot -p --all-databases --flush-logs

12、—flush-privileges

含义:在导出mysql数据库之后,发出一条FLUSH PRIVILEGES 语句。为了正确恢复,该选项应该用于导出mysql数据库和依赖mysql数据库数据的任何时候。 示例:

Terminal window
mysqldump -uroot -p --all-databases --flush-privileges

13、—help

含义:显示帮助信息并退出。 示例:

Terminal window
mysqldump --help

14、—host, -h

含义:需要导出的主机信息 示例:

Terminal window
mysqldump -uroot -p --host=localhost --all-databases

15、—ignore-table

含义:不导出指定表。指定忽略多个表时,需要重复多次,每次一个表。每个表必须同时指定数据库和表名。例如:—ignore-table=database.table1 —ignore-table=database.table2 …… 示例:

Terminal window
mysqldump -uroot -p --host=localhost --all-databases --ignore-table=mysql.user

16、—lock-all-tables, -x

含义:提交请求锁定所有数据库中的所有表,以保证数据的一致性。这是一个全局读锁,并且自动关闭—single-transaction 和—lock-tables 选项。 示例:

Terminal window
mysqldump -uroot -p --host=localhost --all-databases --lock-all-tables

17、—no-create-db, -n

含义:只导出数据,而不添加CREATE DATABASE 语句。 示例:

Terminal window
mysqldump -uroot -p --host=localhost --all-databases --no-create-db

18、—no-create-info, -t

含义:只导出数据,而不添加CREATE TABLE 语句。 示例:

Terminal window
mysqldump -uroot -p --host=localhost --all-databases --no-create-info

19、—no-data, -d

含义:不导出任何数据,只导出数据库表结构。 示例:

Terminal window
mysqldump -uroot -p --host=localhost --all-databases --no-data

20、—password, -p

含义:连接数据库密码

21、—port, -P

含义:连接数据库端口号

22、—routines, -R

含义:导出存储过程以及自定义函数。 示例:

Terminal window
mysqldump -uroot -p --host=localhost --all-databases --routines

23、—tables

含义:覆盖—databases (-B)参数,指定需要导出的表名,在后面的版本会使用table取代tables。 示例:

Terminal window
mysqldump -uroot -p --host=localhost --databases test --tables test

24、—triggers

含义:导出触发器。该选项默认启用,用—skip-triggers禁用它。 示例:

Terminal window
mysqldump -uroot -p --host=localhost --all-databases --triggers

25、—user, -u

含义:指定连接的用户名。

26、—version, -V

含义:输出mysqldump版本信息并退出

27、—where, -w

含义:只转储给定的WHERE条件选择的记录。请注意如果条件包含命令解释符专用空格或字符,一定要将条件引用起来。 示例:

Terminal window
mysqldump -uroot -p --host=localhost --all-databases --where=” user=’root’”

28、—xml, -X

含义:导出XML格式. 示例:

Terminal window
mysqldump -uroot -p --host=localhost --all-databases --xml