質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.59%

C++ ファイルコピーの方法

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 12K+

tuyudaku

score 60

C++にて、ファイルコピーを行なう関数を作ろうと思ったのですが
いくつかの方法がありどの方法でやるかを迷っています

皆さんならどの方法で実装するかを教えてください
それぞれの長所などがいまいち分からず選びきれていない状況です
よろしくお願いします

サイトに載っていたコードを参考にしています

//system関数を利用した方法
system( "cp test.txt /tmp" );
void CopyFile( const char *from_file_name, const char *to_file_name )
{
    //streambuf_iteratorとcopy()を利用した方法

    ifstream is( from_file_name, ios::in | ios::binary );
    ofstream os( to_file_name, ios::out | ios::binary );

    // ファイルコピー
    istreambuf_iterator<char> iit(is);
    istreambuf_iterator<char> end;
    ostreambuf_iterator<char> oit(os);
    copy( iit, end, oit );
}
void CopyFile( const char *from_file_name, const char *to_file_name )
{
    //fstream::rdbuf()と<<を使った方法
    ifstream is( from_file_name, ios::in | ios::binary );
    ofstream os( to_file_name, ios::out | ios::binary );

    // ファイルコピー
    os << is.rdbuf();
}
void my_copy(char *from[], char *to[]) {
    //C言語標準ライブラリを利用した方法
    FILE *f1, *f2;
    int c;

    f1 = fopen(from, "r");
    if (!f1) err(from);

    file_exist(to);
    f2 = fopen(to, "w");
    if (!f2) err(to);

    while ((c = fgetc(f1)) != EOF) {
        if (fputc(c, f2) == EOF) err(to);
    }

    fclose(f2);
    fclose(f1);
}

こんな方法があるよ
こっちの方が安全だよ、という情報がありましたら
よろしくお願いします

---追記
C++17は私の環境では使用できないのでstd::filesystem::copyの方法は無しでお願いします

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+2

こんにちは。

ファイルをコピーするだけなら、system関数か、std::copyですね。
Cライブラリは使わないで済むなら避けたいですし、ファイルを一度全部読むのはファイルが小さいことが判っている時だけですね。

ただ、多くの場合、ファイルの列挙やフォルダ生成等も一緒に必要になるので、C++17が使えないなら、boost::filesystemを使うだろうと思います。もし、既にQt等を使っているならそれらのライブラリを使います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/02 09:20

    >Cライブラリは使わないで済むなら避けたいですし
    やはりそうなんですね
    C++を使っているならなるべくCライブラリを避けて作ろうと思っていたのですが
    そう考えるとsystem関数のようなシステムコールなどはどうなるのだろうと思って質問しました

    >ファイルを一度全部読むのはファイルが小さいことが判っている時だけですね
    1M程が想定され、可変であるので
    やはりあまり現実的ではないですね

    >もし、既にQt等を使っているならそれらのライブラリを使います。
    その手もありましたね、まさにQtを使っています。
    ただ、画面系以外の部分ではQtライブラリを使わないみたいな
    暗黙の了解的なのが出来ているのでそこは要相談といった感じですw

    回答ありがとうございました

    キャンセル

checkベストアンサー

+1

system関数が使えるのならば、それでいいと思います。

問題は移植性を考慮して使えない場合です。
ここで出てる他の3つの方法(std::copy, rdbuf, C)には問題があります。

  1. std::copy
    バイト単位の読み込み・書き込みになるので容量に比例して遅くなります。
  2. rdbuf
    超大容量なファイルをコピーする際に問題が生じる可能性があります。
  3. C
    1と同じでバイト単位で読み込み・書き込みをしているので遅くなります。
    さらに、"b"オプションをつけずにファイルを開いているのでWindows環境において問題が生じます。

なので適当に修正して

#include<cstdio>
void my_copy(char * const from[], char * const to[]) {
    constexpr std::size_t BUFSIZE = 4096; // とりあえず4KB
    auto src = fopen(from, "rb");
    if (!src) err(from);

    auto dst = fopen(to, "wb");
    if (!dst) err(to);

    for(char buf[BUFSIZE]; auto size = fread(buf, 1, BUFSIZE, src);){
        fwrite(buf, 1, size, dst);
    }
    fclose(dst);
    fclose(src);
}

まぁ、非windows環境でsystem、windows環境でCopyFileが楽でいいと思いますけどね

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/02 09:11

    >system関数が使えるのならば、それでいいと思います。
    なるほど、Linuxでの使用しか考えていないのなら
    system関数がベターな方法なんですね

    バイト単位でのコピー方法の利点は
    どこで、なんのエラーが起きているのかが拾いやすいということでしょうかね?

    回答ありがとうございました

    キャンセル

  • 2018/11/02 09:15 編集

    ファイルが途中で書き換えられたら?削除された場合は?
    win環境ではファイルの作成日時をコピーする?

    なんていう細々したものを
    OSの仕様に準じる
    と一言で済ませられるのがsystem/CopyFile最大の利点です。

    ---

    バイト単位の利点については途中で書き換えられた場合に追随できる点ですが
    そもそも、そんな事されたらマトモなファイルになるかは微妙なので
    個人的には使いたくないなぁと思います。

    ファイルサイズを取ってきてファイルサイズの10%or10MB程度の小さい方
    をバッファサイズとして使うコピーが個人的には理想です。

    キャンセル

+1

C++17 を想定できるのであれば std::filesystem::copy を使うというのもひとつの方法です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/01 17:22

    あぁ...ごめんなさい...
    書かなきゃと思っていたことを書くの忘れていました...

    C++17は私の環境では使えないのでそれは除外してください...
    C++17さえ使えれば...

    回答ありがとうございました

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る