본문 바로가기

Language/Go

[Go] - web programming : csv, gob 패키지 다루기

파일 저장

 

- 메모리에 데이터를 저장하는게 빠르지만 휘발성 데이터임 (임시로 저장)

- 메모리에 저장된 데이터를 비 휘발성 저장 장치(하드)에 저장시키자

- csv는 텍스트포맷(콤마로 구분), gob는 바이너리 포맷 으로 serializing, cahing할 때 효과적 이라 함

 

 

CSV 읽기 쓰기

 

1. 데이터 정의 및 csv파일 생성

- 게시판 어플리케이션을 만든다 생각했을 떄, 아래와 같이 struct를 정의한다.

type Post struct {
	Id int
	Content string
	Author string
}

- post파일을 저장할 csv파일을 생성해준다. (defer와 panic은 추후 공부하자)

csvFile, err := os.Create("posts.csv")
	if err != nil {
		panic(err)
	}
defer csvFile.Close()

 

2. csv파일에 저장할 임의의 데이터를 생성하고, csv파일에 저장한다.

- csv에 정의할 데이터를 만들어 준다.

allPosts := []Post {
	{Id: 1, Content: "Hello World!", Author: "John"},
	{Id: 2, Content: "안녕하세요!", Author: "창종"},
	{Id: 3, Content: "Aloha", Author: "Anna"},
	{Id: 4, Content: "I'am John", Author: "John"},
}

- csv.NewWriter로 writer를 생성하고, csv에 저장할 string array에 데이터를 담아 writer에 데이터를 저장한다. Flush 함수를 호출을 하여 버퍼를 비워 작성한다.

writer := csv.NewWriter(csvFile)
	 for _, post := range allPosts {
		line := []string{strconv.Itoa(post.Id), post.Content, post.Author}
		err := writer.Write(line)
		if err != nil {
			panic(err)
		}
	}
writer.Flush()

3. csv 파일 읽기

- csv 파일을 읽고, reader를 생성하고 FieldsPerRecode 값을 설정해준다. (양수: 정확한 필드의 수, 음수: 필드의 수가 부족해도 됨)

file, err := os.Open("posts.csv")
if err != nil {
	panic(err)
}
defer file.Close()

reader :=csv.NewReader(file)
reader.FieldsPerRecord = -1
record, err := reader.ReadAll()
if err != nil {
	panic(err)
}

4. 읽은 record 순회

- 읽은 데이터(record)를 순회하며 객체를 생성하여 데이터를 메모리에 저장한다.

var posts []Post
for _, item := range record {
	id, _ := strconv.ParseInt(item[0], 0, 0)
	post := Post{Id: int(id), Content:item[1], Author:item[2]}
	posts = append(posts, post)
}

 

gob 패키지 다루기

 

1. store: data interface를입력받아 binray로 encoding 

- gob 패키지는 바이너리 데이터인 gob의 스트림을 관리하며 인코더와 디코더 간 변화를 지원(일반 파일io랑 비슷)

- data --> endcoding --> buffer 데이터를 파일에 작성

func store(data interface{}, filename string) {
	buffer := new(bytes.Buffer)
	encoder := gob.NewEncoder(buffer)
	err := encoder.Encode(data)
	if err != nil {
		panic(err)
	}
	err = ioutil.WriteFile(filename, buffer.Bytes(), 0600)
	if err != nil {
		panic(err)
	}
}

2. load: encoding한 파일을 다시 decoding하여 interface에 저장

- ioutil로 raw 파일을 읽고, decoding

- raw --> decoding --> data

func load(data interface{}, filename string) {
	raw, err := ioutil.ReadFile(filename)
	if err != nil {
		panic(err)
	}
	buffer := bytes.NewBuffer(raw)
	dec := gob.NewDecoder(buffer)
	err = dec.Decode(data)
	if err != nil {
		panic(err)
	}
}

 

test code

- 간단한 post 데이터를 store, load해보고 출력하는 코드

func main() {
	post := Post{Id: 1, Content: "Hello World!", Author: "dksshddl"}
	store(post, "post1")
	var postRead Post
	load(&postRead, "post1")
	fmt.Println(postRead)
}

 


어려운 부분은 아닌데, 파일을 다룰때 defer, panic 함수의 구체적 사용법, 이유등을 더 공부해야 겠다.