Goの標準パッケージを入門レベルで学ぼうと思って書き残したメモです。
スターティングGo言語の7章の以下のパッケージについて記載しています。
単なる写経に近いクソ記事ですw。
- osパッケージ
- timeパッケージ
osパッケージ
import "os"
ホスト名の取得
func main() {
host, _ := os.Hostname()
fmt.Println(host)
}
環境変数
func main() {
// 環境変数一覧を表示
for _, env := range os.Environ(){
fmt.Println(env)
}
// 環境変数の名前を指定して取得
fmt.Println(os.Getenv("HOME"))
}
プログラムの終了
func main() {
// 終了コード1で終了する
os.Exit(1)
}
プロセス情報
func main() {
fmt.Printf("プロセスID: %v\n", os.Getpid())
fmt.Printf("親プロセスID: %v\n",os.Getppid())
fmt.Printf("ユーザID: %v\n", os.Getuid())
fmt.Printf("グループID: %v\n", os.Getgid())
}
log.Fatal
func main() {
_, err := os.Open("README.md")
if err != nil {
log.Fatal(err)
}
}
コマンドライン引数
func main() {
for _, v := range os.Args {
fmt.Println(v)
}
}
ファイル操作
読み込み専用ファイルのオープン
func main() {
f, err := os.Open("README.md")
if err != nil {
log.Fatal(err)
}
defer f.Close()
}
os.File
func main() {
f, err := os.Open("README.md")
if err != nil {
log.Fatal(err)
}
/* []byte型のスライスにファイルの内容を読み込む */
bs1 := make([]byte,128)
n ,err := f.Read(bs1) // nは実際に読み込んだバイト数
if err != nil {
log.Fatalln(err)
}
fmt.Println(n)
/* ファイルのオフセットを指定して読み込む */
bs2 := make([]byte, 128)
n2, err := f.ReadAt(bs2, 10) // 10バイト目から読み込む
if err != nil {
log.Println(err)
}
fmt.Println(n2)
/* ファイルのステータス取得 */
fi, err := f.Stat()
if err != nil {
log.Fatal(err)
}
fmt.Println(fi.Name()) // ファイル名
fmt.Println(fi.Size()) // ファイルサイズ
fmt.Println(fi.Mode()) // ファイルのモード
fmt.Println(fi.ModTime()) // ファイルの最終更新時間
fmt.Println(fi.IsDir()) // ディレクトリかどうか
}
実際にファイルを読み込む処理を書くと、こんなかんじでしょうか。
func readFile(filepath string) (lines []string) {
f, err := os.Open(filepath)
if err != nil {
log.Fatal(err)
}
buf := make([]byte, 1024)
for {
n, err := f.Read(buf)
if err != nil {
log.Fatal(err)
}
if err == io.EOF { // EOFの場合抜ける
break
}
str := string(buf[:n])
fmt.Println(str)
lines = append(lines, str)
}
return
}
func main() {
filepath := "README.md"
for _, line := range readFile(filepath) {
fmt.Println(line)
}
}
新規ファイルの作成
func main() {
f, err := os.Create("NewFile.txt") // ファイル名を指定して新規作成
if err != nil {
log.Fatal(err)
}
f.Write([]byte("Hello, World\n")) // ファイルに[]byte型の内容を書き込み
f.WriteAt([]byte("Golang"), 7) // オフセットを指定して書き込み
f.Seek(0, io.SeekEnd) // ファイルの末尾にオフセットを移動
f.WriteString("Year") // 文字列をファイルに書き込み
}
ファイルオープン詳細
os.OpenFile
を使う。
func main() {
f, err := os.OpenFile("README.md", os.O_RDONLY, 0666)
if err != nil {
log.Fatal(err)
}
fmt.Println(f.Name())
defer f.Close()
}
フラグ | 意味 |
---|---|
O_RDONLY | 読み込み専用 |
O_WRONLY | 書き込み専用 |
O_RDWR | 読み書き可能 |
O_APPEND | ファイルの末尾に追記 |
O_CREATE | ファイルが存在しなければ新規作成 |
O_TRUNC | 可能であればファイルの内容をオープン時に空にする |
ファイルの削除
func main() {
if err := os.Remove("NewFile.txt"); err != nil {
log.Fatal(err)
}
}
ファイル名の変更と移動
func main() {
if err := os.Rename("NewFile.txt", "BackupFile.txt"); err != nil {
log.Fatal(err)
}
}
ディレクトリ操作
カレントディレクトリ
func main() {
dir, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
fmt.Println(dir)
}
ディレクトリの読み込み
func main() {
f, err := os.Open(".")
if err != nil {
log.Fatal(err)
}
defer f.Close()
// カレントディレクトリ下のディレクトリ名を列挙
fis, err := f.Readdir(0)
for _, fi := range fis {
if fi.IsDir() {
fmt.Println(fi.Name())
}
}
}
ディレクトリの作成
func main() {
// カレントディレクトリ配下にディレクトリを作成
if err := os.Mkdir("foo", 0775); err != nil {
log.Fatal(err)
}
// カレントディレクトリ配下にディレクトリを一括作成
// mkdir -p に相当
if err := os.MkdirAll("foo/bar/baz", 0755); err != nil {
log.Fatal(err)
}
}
ディレクトリの削除
func main() {
if err := os.Remove("NewFile.txt"); err != nil {
log.Fatal(err)
}
if err := os.RemoveAll("foo") err != nil {
log.Fatal(err)
}
}
その他のファイル操作
シンボリックリンクの操作
func main() {
// シンボリックリンクbar.txtを作成
if err := os.Symlink("foo.txt", "bar.txt"); err != nil {
fmt.Println(err)
}
// シンボリックリンクのリンク先を読み込む
path, err := os.Readlink("bar.txt")
if err != nil {
log.Fatal(err)
}
fmt.Println(path)
}
timeパッケージ
import "time"
現在の時刻取得
func main() {
t := time.Now()
fmt.Println(t)
}
指定した時刻の生成
func main() {
t := time.Date(2019, 2, 3, 11, 50, 0, 0, time.Local)
fmt.Println(t)
fmt.Println(t.Year())
fmt.Println(t.Month())
fmt.Println(t.Day())
fmt.Println(t.Weekday())
fmt.Println(t.Hour())
fmt.Println(t.Minute())
fmt.Println(t.Second())
fmt.Println(t.Nanosecond())
fmt.Println(t.Zone())
}
メソッド | 戻り値の型 | 意味 |
---|---|---|
Year | int | 年 |
YearDay | int | 1~366 |
Month | time.Month | 月 |
Weekday | time.Weekday | 曜日 |
Day | int | 1~31 |
Hour | int | 0~23 |
Minute | int | 0~59 |
Second | int | 0~59 |
NanoSecond | int | ナノ秒 |
Zone | string, int | タイムゾーンとオフセット秒 |
時刻間隔の表現
func main() {
fmt.Println(time.Hour) // 1h0m0s
fmt.Println(time.Minute) // 1m0s
fmt.Println(time.Second) // 1s
fmt.Println(time.Millisecond) // 1ms
fmt.Println(time.Microsecond) // 1µs
fmt.Println(time.Nanosecond) // 1ns
}
文字列からtime.Durationを生成
func main() {
// 文字列からtime.Durationを生成
duration, err := time.ParseDuration("2h30m")
if err != nil {
log.Fatal(err)
}
fmt.Printf("%v : %T", duration, duration) // 2h30m0s : time.Duration
}
time.Durationの計算
func main() {
t := time.Now()
fmt.Println(t) // 2019-02-03 12:01:38.307595 +0900 JST m=+0.000568779
t = t.Add(2*time.Minute + 15*time.Microsecond)
fmt.Println(t) // 2019-02-03 12:03:38.30761 +0900 JST m=+120.000583779
}
時刻の差分を取得
func main() {
t0 := time.Date(2020, 2,1,0,0,0,0,time.Local)
t1 := time.Now()
d := t0.Sub(t1)
fmt.Println(d) // 8699h55m41.548192s
}
時刻の比較
func main() {
t0 := time.Now()
t1 := t0.Add(24 * time.Hour)
fmt.Println(t0) // 2019-02-03 12:09:01.320207 +0900 JST m=+0.000428654
fmt.Println(t1) // 2019-02-04 12:09:01.320207 +0900 JST m=+86400.000428654
// 時刻の比較
fmt.Println(t1.Before(t0)) // false
fmt.Println(t1.After(t0)) // true
}
年月日の増減
func main() {
t0 := time.Date(2019,2,1,0,0,0,0,time.Local)
fmt.Println(t0) // 2019-02-01 00:00:00 +0900 JST
// 1年増やす
t1 := t0.AddDate(1, 0,0)
fmt.Println(t1) // 2020-02-01 00:00:00 +0900 JST
// 1ヶ月減らす
t2 := t0.AddDate(0,-1,0)
fmt.Println(t2) // 2019-01-01 00:00:00 +0900 JST
}
文字列からの時刻生成
func main() {
// 第一引数にフォーマットを指定
// 第二引数がパース対象の文字列
t, err := time.Parse(time.RFC822, "02 Jan 06 15:04 MST")
if err != nil {
log.Fatal(err)
}
fmt.Println(t) // 2006-01-02 15:04:00 +0000 MST
}
第一引数のフォーマットは以下の通り定義されている。
const (
ANSIC = "Mon Jan _2 15:04:05 2006"
UnixDate = "Mon Jan _2 15:04:05 MST 2006"
RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
RFC822 = "02 Jan 06 15:04 MST"
RFC822Z = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
RFC3339 = "2006-01-02T15:04:05Z07:00"
RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
Kitchen = "3:04PM"
// Handy time stamps.
Stamp = "Jan _2 15:04:05"
StampMilli = "Jan _2 15:04:05.000"
StampMicro = "Jan _2 15:04:05.000000"
StampNano = "Jan _2 15:04:05.000000000"
)
自分でフォーマットを定義する場合は、例えば以下のようにする。
注意することとして、フォーマット指定のタイムスタンプは2006年1月2日 15:04:05
で統一されていないといけない。
このフォーマット指定に疑問を抱いたので調べたところ、アメリカの時刻の順番らしい。”1月2日午後3時4分5秒2006年”でとなっていて、1,2,3,4,5,6と並んでいる。
func main() {
t, err := time.Parse("2006年1月2日 15時04分05秒", "2019年2月3日 21時15分00秒")
if err != nil {
log.Fatal(err)
}
fmt.Println(t) // 2019-02-03 21:15:00 +0000 UTC
}
時刻からの文字列生成
func main() {
t := time.Now()
f1 := t.Format(time.RFC822)
f2 := t.Format(time.RFC3339)
f3 := t.Format("2006年1月2日 15時43分28秒")
f4 := t.Format("2006/01/02")
fmt.Printf("f1: %v (%T)\n", f1, f1) // f1: 03 Feb 19 14:05 JST (string)
fmt.Printf("f2: %v (%T)\n", f2, f2) // f2: 2019-02-03T14:05:05+09:00 (string)
fmt.Printf("f3: %v (%T)\n", f3, f3) // f3: 2019年2月3日 14時52分38秒 (string)
fmt.Printf("f4: %v (%T)\n", f4, f4) // f4: 2019/02/03 (string)
}
時刻のUTC変換
func main() {
t := time.Now()
utc := t.UTC() // UTCに変換
fmt.Printf("utc : %v (%T)\n", utc, utc) // utc : 2019-02-03 05:07:07.324682 +0000 UTC (time.Time)
}
時刻のローカルタイム変換
func main() {
t := time.Now()
jst := t.Local() // ローカルタイムに変換
fmt.Printf("jst : %v (%T)\n", jst, jst) // jst : 2019-02-03 14:08:24.109525 +0900 JST (time.Time)
}
UNIX時間との相互変換
func main() {
t := time.Now()
unix := t.Unix()
fmt.Printf("unix : %v (%T)\n", unix, unix) // unix : 1549170553 (int64)
}
指定時間のスリープ
func main() {
for i := 0; i < 10; i ++ {
fmt.Println(i)
time.Sleep(100 * time.Millisecond) // 100msecスリープ
}
}
time.Tick
time.Tick
は、指定した時間間隔ごとに現在時刻を表すtime.Time
型の値が送信されるチャネルを生成する。
func main() {
// 3秒間隔で現在の時刻を送信するチャネルを定義
ch := time.Tick(3 * time.Second)
// 無限ループ
for {
t := <-ch
fmt.Println(t) // 3秒間隔で表示される
}
}
time.After
time.After
は、チャネルに対して指定した時間間隔後に一度だけ現在時刻を表すtime.Time
を送信する。
func main() {
// 5秒後に時刻を送信するチャネル
ch := time.After(5 * time.Second)
// 5秒後に表示される
v := <-ch
fmt.Println(v)
}
A Tour of Goのサンプルではtime.Tick
とtime.After
を組み合わせてselect-for
文で以下のような使い方をしていた。
func main() {
tick := time.Tick(100 * time.Millisecond)
boom := time.After(500 * time.Millisecond)
for {
select {
case <-tick: // tickチャネルから受信したの場合
fmt.Println("tick.")
case <-boom: // boomチャネルから受信した場合はreturnでfor文から抜ける。
fmt.Println("BOOM!")
return
default: // デフォルトの場合は50msecスリープ
fmt.Println(" .")
time.Sleep(50 * time.Millisecond)
}
}
}
今週は週3回のクソ記事投稿目標をなんとか達成。。