[Go] Directory 감지 프로그램을 만들어보자

윤동환·2023년 7월 5일
0

Go

목록 보기
10/18
post-thumbnail

목표

특정 디렉토리에 파일이 생성되면 그 파일을 다른 디렉토리로 옮기기

특정 디렉토리에 log 파일이 쌓인다면 해당파일을 분석하고 처리 및 저장하는 기능이 필요하다고 가정해보자

필요한 기능

  1. monitoring 하고있는 디렉토리에 파일이 추가되었는지 확인
  2. 해당 디렉토리의 파일들을 다른 디렉토리로 옮기기
package main

import (
    "fmt"
    "os"
	"sync"
	"strconv"
)

const store_path = "/home/smsc/sim/go/src/monitoring/store_dir"
var ch = make(chan string, 100)

func check(err error) {
	//go 내장 함수로 호출이 되면 해당 함수는 즉각 멈추고 나머지 defer들을 호출하고 리턴이 되며 이는 상위 콜스택을 따라 올라가가게 되며 마지막은 프로그램이 종료되게 된다.
    if err != nil {
		// log.Fatal(err)
        //panic(e)
		// fmt.Println("error : ", e)
    }
}

func createFile(name string, ch chan string) {
	for prefix_name := 0; prefix_name < 5; prefix_name++ {
   		err := os.WriteFile(name + "/file" + strconv.Itoa(prefix_name), []byte("content" + strconv.Itoa(prefix_name)), 0644)
 	  	check(err)
		// fmt.Println("create file" + name)
		// time.Sleep(time.Second * 1)  //초에 한번씩 파일 생성
	}	
	// close(ch)
}

func sendAllFile(mpath, spath string, file_name string) {

	
	fmt.Println("send : ", spath + "/" + file_name)
	err := os.WriteFile(spath + "/" + file_name, []byte("content" + file_name), 0644)
	check(err)
	path_err := os.Remove(mpath + "/" + file_name)
	check(path_err)
}

func checkDir(path string, ch chan string) {
	files, err := os.ReadDir(path)
	check(err)
	if files != nil {
		for _, file := range files {
			ch <- file.Name()
		}
	} else {
		fmt.Println("dir empty!")
	}
	// time.Sleep(time.Second)
}

func controlFile(path string, ch chan string) {
	for {
		select {	
			case file_name := <- ch:
				sendAllFile(path, store_path, file_name)
			default :
				checkDir(path, ch)
		}
		// time.Sleep(time.Second)
	}
}

func main() {
	monitoring_path := os.Getenv("MONITORINGPATH")
	fmt.Println("monitoring path : ", monitoring_path)

	//monitoring dir 생성 
	err := os.Mkdir(monitoring_path, 0755)
	check(err)

	err = os.Mkdir(store_path, 0755)
	check(err)
	
	//파일 생성하고 ch에 해당 파일 이름 넣기

	var wg sync.WaitGroup
	wg.Add(1)

	go controlFile(monitoring_path, ch)
	go createFile(monitoring_path, ch)

	
	// defer os.RemoveAll(store_path)
	
	wg.Wait()
}

코드 설명

main

  1. 환경 변수로 monitoring할 dir의 경로를 받아온다.
  2. sync 패키지의 WaitGroup을 사용하여 goroutine이 함께끝나도록 제어한다.
    -> thread의 join 느낌
    하지만 이 코드에선 wait()이 동작하지 않는다. 그 이유는 wg.Done()을 하여 wg count를 0으로 바꿔주어야 하는데 파일이 생성되는 것을 지속적으로 monitoring하기 위해 넣지 않았기 때문이다.
    여기에서 wait()은 main goroutine이 끝나지 않도록 하는 역할이다.
  3. controlFile을 우선 호출하여 우선적으로 디렉토리를 검사하고, 이후 createFile을 호출하며 file을 생성해준다.

controlFile

  1. ch이 non-buffer channel이기 때문에 ch에 값이 있으면 case, 값이 없다면 default로 빠진다.

    select는 Goroutine이 다중 커뮤니케이션 연산에서 대기할 수 있게 하기 때문
    때문에 switch처럼 참거짓으로 case를 나눌 수 없고 위처럼 channel 연산으로 가능하다.

  2. case 함수에 go를 붙이지 않은 이유
  • sendAllFile()이나 checkDir()에 go를 붙이면 for문을 돌면서 해당 goroutine이 무한히 만들어진다.
  • checkDir로 디렉토리 file을 받아왔으면 다음엔 send를 하기위해서
    -> 이 때 send를 하면 기존 파일을 지우기 때문에 checkDir 하면서 파일이 중복되어 ch에 들어가지 않음

sendAllFile

  1. 파일을 보내기 위해 동작해야 하지만 현재는 그냥 같은 파일 이름으로 새로생성하고 있음
    -> 추후에 파일을 복사하여 생성할 예정
profile
모르면 공부하고 알게되면 공유하는 개발자

0개의 댓글