C ++内から外部ファイルを実行する

Aug 21 2020

フロントエンドでユーザーにコードを入力するためのテキストエディターを表示するアプリケーションを作成しようとしています。次に、そのコードを実行して結果を返します。自分のバージョンのleetcodeを学習プロジェクトとして構築してみるのは楽しいプロジェクトだと思いました。

現在、これは提供されたコードを実行するために私が行っていることです。私が今実装しているのはそれだけなので、Pythonコードを実行しているとしましょう。

まず、ユーザーが送信したコードを取り込んで、指定されたコードを含むファイルを作成します。

std::string python(std::string code){
    std::string langCommand = "python3 ";
    std::string outFile;

    //I am hoping to parallelize this operation so I add threadID to output
    outFile = createOutFileName("PythonRunner.py");

    std::ofstream output;
    output.open(outFile);
    output << code;
    output.close();
    return langCommand + outFile;
}

次に行うことは、出力ファイルを作成し、以前に作成したファイルを実行することですが、stdout / stderrを別の出力ファイルに送信します。

std::string Program::run(){
    std::string command = createFile(this->lang, this->code);

    this->outputFile = createOutFileName("output.txt");

    std::stringstream newCommand;
    newCommand << command;
    newCommand << ">> ";
    newCommand << outputFile;
    newCommand << " 2>&1";

    system(newCommand.str().c_str());
    std::string output = getOutputFileData(this->outputFile);
    cleanupFiles(command);
    return output;
}

最後に、出力ファイルから取得したものをすべて返します。これがコードの実行方法です。

これを行うもっと簡単な方法があると思います。特に私はファイルにたくさんの書き込みをしてからそれから読み取るので、それを取り除く方法はありますか?

また、将来的には複数の言語を含めたいので、特定の言語に固有のライブラリは使用したくありません。

最後に、これは私の最初のC ++プロジェクトなので、C ++のヒントがあればいいのですが。

編集:私は最終的にこのコードを並列化し、プログラムが実行されているシステムに損傷を与えないようにプログラムをカプセル化する方法を見つけたいと思っています。そのために役立つ外部プログラムがある場合は、私に知らせてください。また、そのstderr / stdoutも教えてください。

編集:誰かが尋ねたように、ここに全体のリポジトリがあります https://github.com/lkelly93/coderunner

回答

2 MartinYork Aug 23 2020 at 00:13

system()あなたがすべきではなくpopen()

違いは、システムがこのプロセスにアクセスできないサブプロセスでコマンドを実行するのに対し、popenはサブプロセスでコマンドを実行します、サブプロセスの入力ストリームと出力ストリームへのアクセスを提供することです。

これにより、サブプロセスを実行し、(標準入力用に指定した入力フィールドから)プロセスへの入力を直接ストリーミングしてから、プロセスからの出力を読み取り、ユーザーインターフェイスの出力フィールドに書き込むことができます。

FILE*  proc = popen(command);
std::string inputFromUser = getUserInputFromUI();
// Using fwrite() correctly left to user.
// You need to check for errors and continue etc.
fwrite(inputFromUser.c_str(), 1, inputFromUser.size(), proc);

char  buffer[100];
std::size_t size;
while((size = fread(buffer, 1, 100, proc)) != 0) {
    // Check for read errors here.
    sendToUserInterface(std::string(bufffer, buffer + size));
}

pclose(proc);
 

関連するソートでは、pythongスクリプトをファイルとして保存する必要はありません。pythonコマンドは、-名前としてを受け入れます。これは、名前付きファイルからではなく、標準入力からスクリプトを読み取ることを意味します。

したがって、(popen()を使用して)pythonコマンドを実行してから、実行するスクリプトを、生成されたファイルの入力ストリームに書き込むことができます。

これにより、中間ファイルが不要になります。

1 aki Aug 21 2020 at 19:56

かなりのもの:

  • コメントを使用して作成された実装とセクションのドキュメント。
  • 単一責任原則に従ったクラス、関数、およびファイル。
  • 関数の説明的な名前。(以下に注意するように変数ではありません)
  • テストフレームワーク!ただし、テストでは、プログラム全体だけでなく、内部関数もチェックする必要があります。

ファイルストリームとファイル名の用語は非常に紛らわしく、関数の戻り値の型や変数宣言を頻繁に検索することになります。

Program::outputFileここでは明確ではないファイルです。私はそれをと間違えましたFILE*

別の場所では、std::ofstream output;出力はプログラムの出力コンテンツのように聞こえますが、それはストリームです!

std::string output = getOutputFileData(this->outputFile); そしてここにまたひもがあります!


コードは絶対パスと相対パスを処理しません。

テストはこれで失敗します:

runnerFiles/0x1005c05c0output.txt does not exist.

このようなコードでは、を使用するのは非常に気が進まないでしょうrm。せいぜい、すべての使い捨てファイルをフォルダに保存し、ユーザーに削除するように依頼してください。


std::stringstream newCommand;
newCommand << command;
newCommand << ">> ";
newCommand << outputFile;
newCommand << " 2>&1";

system(newCommand.str().c_str());

std::stringstream回避できstd::string、最初の項目がstd::string。である限り、連結を直接使用できます。

std::string newCommand = command + ">> " + outputFile + "2>&1";

内のコードgetOutputFileDataその用途FILE*や文字バッファー(あなたも割り当てられませんでした!)(エラー処理を追加)以下に置き換えることができます

  std::ifstream run_output{outFileLocation};
  std::stringstream buffer;
  buffer << run_output.rdbuf();
  return buffer.str();
  • https://stackoverflow.com/questions/2602013/read-whole-ascii-file-into-c-stdstring?noredirect=1&lq=1

線を細かく制御する必要がないので、気にしないでくださいgetline

I / Oにはiostreamを優先します。iostreamは安全で、柔軟性があり、拡張可能です。

  • https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rio-streams

std::ofstream output;
output.open(outFile);
output << code;
output.close();

として短くすることができます

std::ofstream output(outFile);
output << code;

必要がなければ、閉じることを気にしないでください。ときにoutputスコープ外になると、ファイルは自動的に閉じられます。これは、std::vector自動的にクリーンアップされる簡単に破壊可能な配列や配列をすべて削除しないのと同じ理由です。


使用const &またはstd::string_view文字列は読み取り専用です。それらは安価に渡され、コンテンツが変更されないという意図を示しています。

std::string createFile(std::string lang, std::string code)
std::string getOutputFileData(std::string outFileLocation)
bool isSupportedLanguage(std::string lang)
void Program::cleanupFiles(std::string oldCommand)

auto iter = supportedLanguages.find(lang);

C ++ 20にはcontains、数行節約できるようになっています。

  • https://en.cppreference.com/w/cpp/container/unordered_map

this->code

の代わりにthis->_変数に追加または追加して、それらがプライベートメンバーであることを示すことを検討してください。


実装順序が関数の宣言順序に従っている場合は、IMOが読みやすくなります。

ではProgram、コンストラクターはファイルの下部ではなく上部に移動できます。

  • https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#nl16-use-a-conventional-class-member-declaration-order