67757


ファイルを連番で作成したいのですが、ただ連番で作成するのではなく、作成先のフォルダ内に同じファイル名があれば次の数字でファイルを作成したいです。  
仕様としては以下の通りです。

フォルダ内に同じファイルがなければ`text01.txt`を作成

フォルダ内に

> text01.txt  
>  text02.txt  
>  text03.txt

があるときは`text04.txt`を作成

といったようにしたいです。  
どなたか教えていただけないでしょうか。  
よろしくお願いいたします。

4月から研究室に配属し、プログラムを勉強し始めた初心者ですのであまり詳しいことはわかりませんが詳細を追記いたします。  
OSはできればWindowsとMac両方で動くほうが好ましいですが、どちらか片方でもかまいません。  
コンパイラ/ライブラリ/フレームワークについては調べたのですがよく分かりませんでした。ごめんなさい。ファイルの中身は、既にできているプログラムに計算をしてもらうので実際にファイルを作成するといった風になります。  
番号の桁数は4桁ほど使用できるようになればいいなと考えています。  
よろしくお願い致します。


CC BY-SA 4.0
2020-06-17T06:34:13.757
67751
2020-06-19T08:49:38.830
2020-06-17T08:20:43.893
question
c++
c++で連番のファイル名を作成する方法


質問に対する直接的な回答ではありません。方針レベルの回答です。  
仮定が多いので、条件をしぼり込めれば具体的な回答が得やすいと思います。

  * text01.txt、text02.txtの順にファイルの存在をチェックして、存在しなければファイルを作成するのが簡単です。  
ファイルの通番が4桁もあるなら、ディレクトリを読んだ方がよいかもしれません。

  * ファイル名の歯抜け(※)を想定しなければならないなら、ディレクトリを読んでパターンにマッチするファイルの存在を確認する必要があります。  
※text01.txtとtext03.txtが存在し、text02.txtが存在しないケース

  * 作成するプログラムの同時実行の考慮が必要なら排他制御が必要です。


CC BY-SA 4.0
2020-06-17T09:05:11.317
67757
2020-06-17T09:05:11.317
35558
67751
answer


条件にぴったりフィットしている訳ではないけれども、ファイル名に連番を付ける考え方の例の記事がこちら。  
[0埋めの連番が振ってあるファイル名を得たい](https://canon4444.hatenablog.com/entry/2016/04/14/142636)  
[連番ファイル名を発生させる](https://ryamada.hatenadiary.jp/entry/20151025/1445686218)  
[C++における連番ファイルの作り方](http://shimaphoto03.com/program/file-rules/)

* * *

WindowsとMacで同じ実行ファイルが動作することはあり得ないですが、(なるべく)同じソースから作ったプログラムとすることは出来るでしょう。  
C++では、C++17からサポートしているstd::filesystemを使うのが良さそうです。

[filesystem - cpprefjp
C++日本語リファレンス](https://cpprefjp.github.io/reference/filesystem.html)  
[[C++]
filesystemの標準入りが嬉しすぎてライブラリを作った話](https://qiita.com/Kogia_sima/items/7ee25f8b4886fc24fee2)  
[C++17のFilesystemを使ってみた](https://qiita.com/ueken0307/items/4d866bb78e9f4fe6232d)  
[C++
ファイルI/Oが超絶楽になるfilesystem](https://hakase0274.hatenablog.com/entry/2019/09/03/235304)

ただMacは注意が必要かもしれません。  
[Xcode付属のclangだとC++のfilesystemは動かなかった話](https://mem-
archive.com/2019/08/17/post-2016/)

* * *

実際には以下のような記事を参考にしつつ、既存ファイルを検索してリスト化し、存在していない名前のファイルを作成していくパターンでしょうか。  
エラー対処とか細かい場合分けの処理も必要ですが、作っていませんので適宜補完してください。

[list all files with extensions that match a
regex](https://rextester.com/SAY51073)  
[std::vector::empty](https://cpprefjp.github.io/reference/vector/vector/empty.html)  
[std::sortでstd::vectorを昇順でソートする例](https://kaworu.jpn.org/cpp/std::sort#std::sort.E3.81.A7std::vector.E3.82.92.E6.98.87.E9.A0.86.E3.81.A7.E3.82.BD.E3.83.BC.E3.83.88.E3.81.99.E3.82.8B.E4.BE.8B)  
[C++でベクターに特定の要素が含まれているかどうかを確認する](https://www.techiedelight.com/check-vector-
contains-given-element-cpp/)  
[std::stringでprintfのような書式指定を行う方法
(C++11版)](http://pyopyopyo.hatenablog.com/entry/2019/02/08/102456)

こんな感じになるでしょう。(WindowsのVSC2019でしか試していませんが)

[code]

    #include <iostream>
    #include <string>
    #include <vector>
    #include <filesystem>
    #include <fstream>
    #include <regex>
    #include <type_traits>
    #include <algorithm>
    
    namespace fs = std::filesystem;
    
    // 定数をあらかじめまとめて定義 - コマンドラインパラメータで渡せるようにしておくのも良い
    static const fs::path target_dir = "Path/To/Folder";  // 実際の対象フォルダに書き換える
    std::string nameprefix = "test";
    std::string nameext = ".txt";
    static std::size_t startcolumn = nameprefix.length();
    static int numberingdigit = 4;  // 番号に割り当てる桁数 
    static std::size_t numberingbuffsize = 5;
    std::regex pattern = std::regex(nameprefix + "(\\d{4})" + nameext);
    static int startnumber = 1;      // ナンバリングの開始番号 1, 0, あるいは他の値
    static int maxmumnumber = 9999;  // ナンバリングの最大番号 この番号を含んで作成する
    
    // [std::stringでprintfのような書式指定を行う方法 (C++11版)](http://pyopyopyo.hatenablog.com/entry/2019/02/08/102456)
    template <typename ... Args>
    std::string value_format(const std::string& fmt, Args ... args)
    {
        size_t len = std::snprintf(nullptr, 0, fmt.c_str(), args ...);
        std::vector<char> buf(len + 1);
        std::snprintf(&buf[0], len + 1, fmt.c_str(), args ...);
        return std::string(&buf[0], &buf[0] + len);
    }
    
    // ファイル名・パス名を組み立ててファイル作成
    int createnumberingfile(int n)
    {
        int result = 0;
        std::string numbering = value_format("%04d", n);
        std::string filepath = target_dir.string() + "/" + nameprefix + numbering + nameext;
        std::ofstream outfilestream(filepath);
        outfilestream.close();
        return result;
    }
    
    // メインルーチンの入り口
    int main()
    {
        // 対象フォルダが無ければ作成しておく。
        // [Create file with filesystem C++ library](https://stackoverflow.com/q/36775493/9014308)
        std::filesystem::create_directories(target_dir);
    
        // 既存ファイルの検索
        // [list all files with extensions that match a regex](https://rextester.com/SAY51073)
        using iterator = std::conditional< false, fs::recursive_directory_iterator, fs::directory_iterator >::type;
        const iterator end;
        std::vector<fs::path> filelist;
        for (iterator iter{ target_dir }; iter != end; ++iter)
        {
            const std::string filename = iter->path().filename().string();
            if (fs::is_regular_file(*iter) && std::regex_match(filename, pattern)) filelist.push_back(filename);
        }
    
        int result;
    
        // 既存ファイルが無いならすべて作成する
        // [std::vector::empty](https://cpprefjp.github.io/reference/vector/vector/empty.html)
        if (filelist.empty())
        {
            for (int i = startnumber; i <= maxmumnumber; i++)
            {
                result = createnumberingfile(i);
            }
        }
        else
        {
            std::vector<int> existingnumbers;
    
            // 既に存在する番号のリストをintで作成する
            for (const auto& file_name : filelist) {
                existingnumbers.push_back(std::stoi((file_name.string().substr(startcolumn, numberingdigit)), nullptr, 10));
            }
    
            // [std::sortでstd::vectorを昇順でソートする例](https://kaworu.jpn.org/cpp/std::sort#std::sort.E3.81.A7std::vector.E3.82.92.E6.98.87.E9.A0.86.E3.81.A7.E3.82.BD.E3.83.BC.E3.83.88.E3.81.99.E3.82.8B.E4.BE.8B)
            std::sort(existingnumbers.begin(), existingnumbers.end());
            int existingmax = existingnumbers.back(); // 存在する最大の番号を超えたら以後はチェック不要で作成
    
            for (int i = startnumber; i <= maxmumnumber; i++)
            {
                // [C++でベクターに特定の要素が含まれているかどうかを確認する](https://www.techiedelight.com/check-vector-contains-given-element-cpp/)
                if ( (i > existingmax) || (!std::binary_search(existingnumbers.begin(), existingnumbers.end(), i)) ) {
                    result = createnumberingfile(i);
                }
            }
        }
    }
    
[/code]


CC BY-SA 4.0
2020-06-19T08:49:38.830
67811
2020-06-19T08:49:38.830
26370
67751
answer