커맨드라인 플래그
란 커맨드라인 프로그램에서 옵션을 지정하는 방법
"ls -al" 처럼 커맨드 라인에서 명령어 뒤에 추가로 붙이는 옵션을 지정하는 일반적인 방법
envPtr := flag.String("env", "prod", "환경변수")
cpuPtr := flag.Int("cpu", runtime.NumCPU(), "CPU수")
flag.Parse() // 플래그 값을 읽어 들이기 위해 반드시 필요
spew.Dump(envPtr)
spew.Dump(cpuPtr)
2가지 변수를 입력받을 수 있도록 하고 env를 생략하면 기본 값은 Prod, cpu를 생략하면 기본 값은 현재 시스템 cpu수
로깅
이란 문제가 생겼을 때 당시의 시스템 상태를 알기 위해 로그(log)를 남기는 활동을 말함
go언어에 로깅에 관련된 내장 패키지 있지만 rs/zerolog라는 로깅 패키지를 추천. (메모리 사용량도 적고 기능이 많음)
func main() {
if *envPtr != "prod" {
log.Logger = log.Output(zerolog.ConsoleWriter{
Out : os.StdOut,
TimeFormat: time.RFC3339,
})
}
}
GODOC
go언어로 작성한 주석으로부터 자동으로 문서화를 해주는 프로그램
https://pkg.go.dev/golang.org/x/tools/cmd/godoc
일단 패키지나 구조체,함수,주요변수 위에 아래 예제처럼 주석을 붙임. 보통 패키지에 대한 주석은 doc.go파일을 만들어
그 파일에 기록하는 관행이 있음. 패키지에 대한 설명일 때는 주석이 "Package 패키지명"으로 시작하며 구조체, 함수, 변수 등에
대한 설명인경우 그 이름으로 시작
/*
Package string_util은 문자열형에 관한 유용한 유틸리티 함수들을 모아 놓은 패키지
*/
package string_util
// Stringer 인터페이스는 문자열형을 처리하는 인터페이스
type Stringer interface {
String() string
}
빈 파일을 생성 후 파일에 내용 채워넣기
func main() {
const filename = "test.txt"
fp, err := os.Crearte(filename)
if err!= nul {
log.Panic().Err(err).Msg("파일 생성 실패")
}
defer fp.Close()
_, err = fmt.Fprintf(fp, "Hello World\n")
if err != nil {
log.Panic().Err(err).Msg("파일 기록 실패")
}
contents, err := os.ReadFile(filename)
if err != nil {
log.Panic().Err(err).Msg("파일 내용 읽어오기 실패")
}
spew.Dump(contents)
}
os.Create는 여러 번 실행시켜도 파일 내용을 계속 덮어쓰기 때문에, 파일 내용을 append하는 법을 보자
func main() {
const filename = "test.txt"
fp, err := os.OpenFile(filename, os.O_APPEND | os.O_CREATE | os.O_WRONLY, 0644)
// 이하 생략
}
파일을 다루려면 알아야하는게 있는데 파일 플래그를 보자
- O_RDONLY: read only
- O_WRONLY: writ eonly
- O_RDWR : read and write
- O_CREATE : 파일이 없다면 새로 생성
- O_EXCL : O_CREATE와 사용시 파일은 없어야 함
- O_TRUNC: 쓰기 가능한 모드로 파일이 열리면 파일의 내용을 전부 지워버림
- O_APPEND: 쓰기 할 때 파일의 내용을 추가 가능 하게 함. 즉 전부 지우지 않음
0644는 무슨의미냐면 0으로 시작했기에 8진수 즉 8진수 644란 의미. 각 자리마다 owner,group,others의 뜻을 가지고 있다
- owner : 파일의 소유자. 보통은 파일을 최초 생성한 사람
- group : 리눅스 시스템에서는 계정과 별도로 group으로 계정 그룹을 관리. 계정 그룹이 같은 사람들 의미
- other : 소유자도 아닌 같은 그룹도 아닌 사람들
각 자리마다 rwx를 2진수로 표시. r은 read w은 write x는 executable
101이면 read & executable이고 8진수로 표현하면 5. 111이면 read & write &executable이고 8진수로 표현시 7
일반적으로 디렉토리 만들 때는 0755, 일반 파일을 만들 때는 0644로 만드는 편
파일 이름을 변경하려면 os.Rename을 사용하면 됨
func main() {
oldName := "test.txt"
newName := "testing.txt"
if err := os.Rename(oldName, newName); err != nul {
// 이하 생략
}
}
파일과 디렉토리
-
os.Create(name string) (*File,error) : name이름의 파일이 존재하지 않으면 생성
-
os.Open(name string) (*file, error) : name의 이름을 읽기 전용 모드로 연다
-
os.OpenFile(name string, flag int, perm FileMode) (*file, error) : 지정된 flag와 퍼미션으로 파일 열음
-
os.Stat(name string) (*FileInfo, error) : 파일의 정보를 가져오거나, 파일이 존재하는지 체크하는데 사용
-
os.Rename(oldpath, newpath string) error : oldpath에서 newpath로 이름을 변경
-
os.Mkdir(name string, perm FileMode) error, os.Modkir(name string, perm FileMode) error : 둘다 디렉토리
만들지만 MkdirAll은 서브 티렉토리가 없으면 서브디렉토리도 만들음
-
os.Remove(name string) error : 파일을 지웁니다
-
os.Chmod(name string, mode FileMode) error : 특정 파일의 퍼미션을 변경
json 읽고 쓰기
// test.json
{
"employees": [
{
"name": "Kim",
"email": "[email protected]"
},
{
"name": "Jun",
"email": "[email protected]"
},
{
"name": "seong",
"email" : "[email protected]"
}
]
}
위 json 데이터 구조를 표현하기 위해 2가지 구조체를 만들자
type Employees struct {
Employees []Employee `json:"employees"`
}
type Employee struct {
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
data1 , err := os.Readfile("test.json")
if err != nil {
panic(err)
}
emp := EMployees{}
err = json.Unmarshal(data1, &emp)
if err != nil {
panic(err)
}
spew.Dump(emp)
data2, err := json.MarshalIndent(emp, ""," ")
if err != nil {
panic(err)
}
err = os.WriteFile("test2.json",data2, 0644)
if err != nil {
panic(err)
}
}
Text 읽기/쓰기
func main() {
// rfp, wfp 파일 여는 부분 생략
rsc := bufio.NewScanner(rfp)
rsc.Split(bufio.ScanLines)
wsc := bufio.NewWriter(wfp)
for rsc.Scan() {
line := rsc.Text()
fmt.Println(line)
if _, err := wsc.WriteString(line + "\n"); err != nil {
panic(err)
}
_ = wsc.Flush()
}
}
CSV 읽기/쓰기
Class,Korean,English,Mathematics
Kim,90,80,60
Lee,100,90,90
Park,80,90,70
Jung,40,30,80
func main() {
// rfp, wfp 파일 여는 부분 생략
reader := csv.NewReader(bufio.NewReader(rfp))
writer := csv.NewWriter(bufio.NewWriter(wfp))
for {
row, err := reader.Read()
if err == io.EOF {
break
}
if err != nil {
panic(err)
}
err = writer.Write(row)
if err != nil {
panic(err)
}
writer.Flush()
}
}
create table users (
id int not null AUTO_INCREMENT,
name varchar(50) not null,
email varchar(100) not null,
password varchar(100) not null,
primary key(id)
)
import (
"github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "go1:goldMa$k46@tcp(127.0.0.1:3306)/go1")
if err != nil {
panic(err)
}
defer db.Close()
var name, email string
row := db.QueryRow("SELECT name, email FROM users WHERE id = ?",1)
err = row.Scan(&name, &email)
if err != nil {
panic(err)
}
fmt.Printf("name:%q, email:%q\n", name, email)
}
이번엔 복수개의 row znjfl
func main() {
// db 커넥션 부문 생략
var id int
var name string
rows, err := db.Query("select id, name from users where id < ?", 10)
if err != nil {
panic(err)
}
defer rows.Close()
for rows.Next() {
_ = rows.Scan(&id, &name)
fmt.Println(id, name)
}
}
db.Exec의 결과를 result에 저장하는데 result.LastInsertId() 함수를 통해 마지막으로 insert한 id를 알아낼 수 있다
result.RowsAffected() 함수를 통해 몇개의 row에 영향을 미쳤는지 알 수 있고 update, delete도 비슷한 방식으로 작성할 수 있다
func main() {
//db 커넥션 부문 생략
result, err := db.Exec(
"insert into users values (?, ?, ?, ?)",
3,
"jane doe"
"[email protected]",
"131231154124121313413",
)
if err != nil {
panic(err)
}
n, err := result.LastInsertId()
if err != nil {
panic(err)
}
fmt.Printf("last-insert-id: %d\n" , n)
}
ORM툴인 xorm이 있다. 홈페이지 주소는 https://xorm.io
xorm은 구조체를 통하여 쿼리를 진행한다. users에 해당하는 구조체를 선언하자
type User struct {
Id int
Name,Email,Password string
}
xorm을 사용하여 직관적으로 간단하게 select와 insert를 할 수 있다
func main() {
db, err := xorm.NewEngine("mysql", "go1:goldMa$k456@tcp(127.0.0.1:3306)/go1")
if err != nil {
panic(err)
}
defer db.Close()
var users []User
err = db.Table("users").Where("id > ?", 10).Find(&users)
if err != nil {
panic(err)
}
fmt.Println(users)
newUser := user{
Name : "saechimdaeki"
Email : "[email protected]",
Password: "13141241212141",
}
_, err := db.Table("users").Insert(&newuser)
if err!= nil {
}
}