1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

自作オブジェクトストレージ日記.part2

Last updated at Posted at 2024-10-27

前回 : 自作オブジェクトストレージ日記.part1

第2回 1MBごとにファイルを分割する

前回は20GBのファイルを5GB事に分割しました。今回は1MBごとに分割し、マージします

リード・ソロモン符号を使ったイレイジャーコーディングを利用するための下準備です。
先頭にヘッダーを付け、ファイルサイズを記録しました。これによって最後のファイルサイズが1mBぴったりにならなかったとしても安心です。

package main

import (
	"encoding/binary"
	"fmt"
	"os"

	"github.com/cheggaaa/pb/v3"
)

type Header struct {
	FileSize  uint32 //ブロックのファイルサイズ
	I_Counter uint32 //Iのカウンタ. 0から始まる
}

func main() {
	fmt.Println("Hello World!")
	// binary/inputをバイナリファイルとして読み込み、1MBごとに分割してbinary/fragments/%dに書き込むコード
	//バイナリファイルの先頭には、ファイルサイズをint32で格納しておく(4GBまで対応可能なので1MBだと余裕なはず)
	inputfile := "binary/input.mp4"
	outputdir := "binary/fragments/"

	// inputfileを読み込む
	input, err := os.Open(inputfile)
	if err != nil {
		fmt.Println(err)
		return
	}
	// 関数が終了する際にinputを閉じる
	defer input.Close()

	// inputfileのサイズを取得
	fileInfo, err := input.Stat()
	if err != nil {
		fmt.Println(err)
		return
	}

	fileSize := fileInfo.Size()
	fmt.Println("fileSize: ", fileSize)

	bar := pb.Simple.Start(0)
	bar.SetTotal(fileSize)
	for i := int64(0); i < fileSize; i += 1024 * 1024 {
		// outputfileを作成
		outputfile := fmt.Sprintf("%s%d", outputdir, i/(1024*1024))
		output, err := os.Create(outputfile)
		if err != nil {
			fmt.Println(err)
			return
		}
		// 関数が終了する際にoutputを閉じる
		defer output.Close()

		//残りのサイズを計算(1MB未満の場合は残りのサイズを読み込む)
		restSize := fileSize - i
		if restSize > 1024*1024 {
			restSize = 1024 * 1024
		}

		// 1MB読み込んで変数に保持
		buf := make([]byte, restSize)
		_, err = input.Read(buf)
		if err != nil {
			fmt.Println(err)
			return
		}

		//ヘッダーを作成
		header := Header{
			FileSize:  uint32(restSize),
			I_Counter: uint32(i / (1024 * 1024)),
		}

		//ヘッダーを書き込む
		err = binary.Write(output, binary.BigEndian, header)
		if err != nil {
			fmt.Println(err)
			return
		}

		//バイナリデータを書き込む
		_, err = output.Write(buf)
		if err != nil {
			fmt.Println(err)
			return
		}
		bar.Add64(restSize)

	}
	bar.Finish()
	fmt.Println("分割完了")
	fmt.Println("復元します")
	bar = pb.Simple.Start(0)
	bar.SetTotal(fileSize)
	//バイナリファイルを読み込んで、元のファイルを復元するコード

	//0から始まるIのカウンタを保持する変数
	iCounter := 0

	//復元したファイルを書き込むためのファイルを作成
	outputfile := "binary/output.mp4"
	output, err := os.Create(outputfile)
	if err != nil {
		fmt.Println(err)
		return
	}
	// 関数が終了する際にoutputを閉じる
	defer output.Close()

	//binary/fragments/以下のファイルを読み込む
	for {
		inputfile := fmt.Sprintf("binary/fragments/%d", iCounter)
		input, err := os.Open(inputfile)
		if err != nil {
			break
		}
		// 関数が終了する際にinputを閉じる
		defer input.Close()

		//ヘッダーを読み込む
		var header Header
		err = binary.Read(input, binary.BigEndian, &header)
		if err != nil {
			fmt.Println(err)
			return
		}
		if header.I_Counter != uint32(iCounter) {
			fmt.Println("I_Counter is invalid")
			return
		}

		//バイナリデータを読み込む
		buf := make([]byte, header.FileSize)
		_, err = input.Read(buf)
		if err != nil {
			fmt.Println(err)
			return
		}

		//バイナリデータをoutputに書き込む
		_, err = output.Write(buf)
		if err != nil {
			fmt.Println(err)
			return
		}

		iCounter++
		bar.Add64(int64(header.FileSize))
	}
	bar.Finish()
	fmt.Println("復元正常完了")
}

実行結果

(base) user@user:~/NicojectStorage/part2$ go run .
Hello World!
fileSize:  23783536867
23783536867 / 23783536867 [---------------------------------------------------------------------------------------------------------------------------------------------] 100.00%
分割完了
復元します
23783536867 / 23783536867 [---------------------------------------------------------------------------------------------------------------------------------------------] 100.00%
復元正常完了
(base) user@user:~/NicojectStorage/part2$ diff binary/input.mp4 binary/output.mp4 
(base) user@user:~/NicojectStorage/part2$

無事にファイル再生ができました。これでイレイジャーコーディングの準備が整いました。

次回はハッシュの検証を組み込みます part3に続く

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?