[解決済み] ファイルをコピーする簡単な方法
質問
Goでファイルをコピーする簡単な/速い方法はありますか?
Doc'sで高速な方法を見つけることができず、インターネットで検索しても同様に役に立ちません。
解決方法は?
<ブロッククオートご注意 この回答は、主にファイルへのハードリンクの追加についてであり、コンテンツのコピーについてではありません。
A 頑丈 と 効率的 コピーは概念的には簡単ですが、多くのエッジケースやターゲットOSとその設定によるシステムの制限を処理する必要があるため、実装は簡単ではありません。
単に既存のファイルの複製を作りたいだけなら
os.Link(srcName, dstName)
. これにより、アプリケーション内でバイトを移動する必要がなくなり、ディスク容量を節約することができます。大きなファイルでは、これはかなりの時間とスペースの節約になります。
しかし、様々なOSでハードリンクの動作に異なる制約があります。アプリケーションとターゲットシステムの構成によります。
Link()
の呼び出しは、すべてのケースで動作しない可能性があります。
汎用的で堅牢かつ効率的なコピー関数を1つだけ使用したい場合は、更新の際に
Copy()
に変更します。
- 少なくとも何らかの形でコピーが成功することを確認するためのチェックを行う(アクセス権、ディレクトリの存在など)
-
を使用して、両方のファイルがすでに存在し、同じものであるかどうかを確認します。
os.SameFile
同じであれば成功を返します。 - リンクを試みる、成功したら戻る
- バイトをコピーする(効率的な方法はすべて失敗)、結果を返す
最適化としては、goルーチンの中でバイトをコピーすることで、呼び出し側がバイトコピーでブロックしないようにすることでしょう。そうすると、呼び出し側が成功/エラーのケースを適切に処理するために、さらなる複雑さが生じます。
もし両方が必要なら、2つの異なるコピー関数を用意することになります。
CopyFile(src, dst string) (error)
をブロッキングコピーに、そして
CopyFileAsync(src, dst string) (chan c, error)
これは、非同期の場合、呼び出し元にシグナルチャンネルを渡すものです。
package main
import (
"fmt"
"io"
"os"
)
// CopyFile copies a file from src to dst. If src and dst files exist, and are
// the same, then return success. Otherise, attempt to create a hard link
// between the two files. If that fail, copy the file contents from src to dst.
func CopyFile(src, dst string) (err error) {
sfi, err := os.Stat(src)
if err != nil {
return
}
if !sfi.Mode().IsRegular() {
// cannot copy non-regular files (e.g., directories,
// symlinks, devices, etc.)
return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())
}
dfi, err := os.Stat(dst)
if err != nil {
if !os.IsNotExist(err) {
return
}
} else {
if !(dfi.Mode().IsRegular()) {
return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())
}
if os.SameFile(sfi, dfi) {
return
}
}
if err = os.Link(src, dst); err == nil {
return
}
err = copyFileContents(src, dst)
return
}
// copyFileContents copies the contents of the file named src to the file named
// by dst. The file will be created if it does not already exist. If the
// destination file exists, all it's contents will be replaced by the contents
// of the source file.
func copyFileContents(src, dst string) (err error) {
in, err := os.Open(src)
if err != nil {
return
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return
}
defer func() {
cerr := out.Close()
if err == nil {
err = cerr
}
}()
if _, err = io.Copy(out, in); err != nil {
return
}
err = out.Sync()
return
}
func main() {
fmt.Printf("Copying %s to %s\n", os.Args[1], os.Args[2])
err := CopyFile(os.Args[1], os.Args[2])
if err != nil {
fmt.Printf("CopyFile failed %q\n", err)
} else {
fmt.Printf("CopyFile succeeded\n")
}
}
関連
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] ファイルのコピー方法について教えてください。
-
[解決済み] scpを使ってリモートからローカルにフォルダをコピーするにはどうしたらいいですか?
-
[解決済み] Gitで1つのファイルの作業コピーの変更を元に戻す?
-
[解決済み] ファイルの内容からJavaの文字列を作成するにはどうすればよいですか?
-
[解決済み] Goでマップにキーが含まれているかどうかを確認するには?
-
[解決済み] ファイルが使用中であるかどうかを確認する方法はありますか?
-
[解決済み] Javaでオブジェクトをコピーするにはどうしたらいいですか?
-
[解決済み] Javaでファイルをコピーする標準的な簡潔な方法?
-
[解決済み] Groovyでファイルを文字列に読み込むには?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] System.ComponentModel.Win32Exception (0x80004005): ixwebhosting [closed]でアクセスが拒否されました。
-
[解決済み] ファイルをコピーする簡単な方法
-
[解決済み] .metaファイルとは何ですか?なぜUnityは私のすべてのアセットに対してそれを作成するのですか?
-
[解決済み] Haskellファイル読み込み
-
error :expectation initializer before
-
[解決済み] makeファイルの「実行」方法
-
[解決済み] VS 2012。ソリューションエクスプローラーを現在のファイルまでスクロールする
-
[解決済み】Goでファイルの読み書きをする方法
-
[解決済み】バッチファイルを使って、テキストファイルに書き込むには?
-
[解決済み] Ant タスクで、ファイルが存在する場合のみ Ant ターゲットを実行する?