LoginSignup
1
2

More than 5 years have passed since last update.

Go言語でファイルをコピーするコマンドを作成する

Posted at

普段はPHPばかり書いているのだが,
多少なりとも低レイヤーなことがやりたかったのでGoで簡単なコマンドをつくってみました。

まず,以下のようなcp.goというソースを作成して
go build cp.go
を実行。

cp.go
// 指定したファイルをコピーする実行ファイル


package main;

//import "bufio";
import "os";
//import "io";
//import "io/ioutil";
import "flag";
import f  "fmt";

    // グローバル空間で変数を宣言
    var sourceFile *string = new (string);
    var destinationFile *string = new (string);
    var e error;
    var capacity *int = new(int);
// main関数(エントリポイント)
func main () {
    // コマンドライン引数を取得
    flag . StringVar(sourceFile, "s", "-", "-s コピーしたいファイルを指定");
    flag . StringVar(destinationFile, "d", "-", "-d コピー後のファイルパスを指定");
    flag . IntVar(capacity, "c", 1, "どの程度の容量でコピーを進めるか")
    flag . Parse();

    // コピー元ファイルの存在チェックを行う
    if _, e = os.Stat(*sourceFile); e != nil {
        f.Printf("sourceFileが存在しません。");
        os.Exit(1);
    }
    if _, e = os.Stat(*destinationFile); e == nil {
        f.Printf("destinationFileが既に存在します。");
        os.Exit(1);
    }

    // まず読み込み元のファイルのサイズを取得する
    var size int = 0;
    var temp int = 0;
    var ensureSize int = 4096 * (*capacity); // 読み込んだ一時的なバイトを保持する
    tempArray := make([]byte, ensureSize);
    var d []byte;
    // プログラム終了時に実行
    var fp *os.File;
    fp, e = os.Open(*sourceFile);
    if (e != nil) {
        f.Printf("ファイルの読み込みに失敗しました。");
        os.Exit(1);
    }

    var newFp *os.File;
    newFp, e := os.Create(*destinationFile);
    if (e != nil) {
        f.Printf("読み込み失敗");
        os.Exit(1);
    }
    defer fp.Close();
    defer newFp.Close();
    for
    {
        // 指定したサイズ分ずつファイルポインタから読み込んでいく。
        temp , e = fp.Read(tempArray);
        d = tempArray[0:temp];
        if (temp == 0) {
            // 読み込みが完了後,ループを抜ける
            break;
        }
        newFp . WriteAt(d, int64(size));
        // 次から書き込むオフセット値を設定
        size = size + temp;
    }
    os . Exit(0);
}

今回はwindows上で実行したので
できあがったバイナリはcp.exeというファイル。

コマンドプロンプト上で
cp -s source.mp4 -d desitnation.mp4 -c 10などと行ったコマンドを叩くと
ファイルをコピーします。

ただそれだけなのですが,

cp.go

        // 指定したサイズ分ずつファイルポインタから読み込んでいく。
        temp , e = fp.Read(tempArray);
        d = tempArray[0:temp];
        if (temp == 0) {
            // 読み込みが完了後,ループを抜ける
            break;
        }
        newFp . WriteAt(d, int64(size));
        // 次から書き込むオフセット値を設定
        size = size + temp;

上記の箇所で読み取ったバイト数を正確なバイト数をコピーするため

        temp , e = fp.Read(tempArray);

戻り値のtempというint型が読み取ったバイト数となりますが

読み取ったバイト数分以上のキャパシティのスライスにならないように
スライス式で必要な長さにカットしたものをWriteAtメソッドの第一引数に渡しています。

1
2
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
2