実現したいこと
あるオブジェクトを読み込んで内容をJSONファイルに出力する処理を書いています。
ある条件になったときはファイルに保存せずに終了したいのですがどのようなやり方があるでしょうか。
該当のソースコード
FILE* fp;
char buf[512];
fp = fopen(path.c_str(), "wb");
FileWriteStream ws(fp, buf, sizeof(buf));
PrettyWriter<FileWriteStream> writer(ws);
for (Object o : objects)
{
// 書き込む処理
}
fclose(fp);
試したこと
現状は fopen
する前にあらかじめ for 文で objects をすべて走査し、該当する条件になったときは return
してしまうコードにしています。
このやり方だと objects を2回走査しなければならないためスマートではありません。
他には該当する条件になったときはファイルを保存した後に削除してしまうという方法もあると思いますが、これも余計なことをしていますよね。
そもそもファイルを保存したくないのです。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
+6
こんにちは。
std::stringstreamへ出力しておいて、必要な時にファイルへ書き出すのではどうでしょう?
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
checkベストアンサー
0
現状の作りで正しいと思います。
取りうる選択肢は以下の2つだけです。
・現状の形を維持する
・正常なデータのみが書き込み処理に到達するようにする
1回チェックしてから書き込むので普通ですから、物凄くピーキーな処理以外ではあまり気にしない方が良いと思います。物理的に書き込む時間とインメモリをチェックする時間には大きな開きがありますから。
fopenとか生書きで直後にobjectを走査するコードがあるとしたら、走査回数を気にするよりよほど問題だと思います。
質問の要件で、僕の場合のC++における理想のコードは以下のような形です。
(以下Embarcadero社製のC++Builderを使っているコードなので違和感があるかもしれませんが)
void WriteObjectsToJson(String path, const std::vector<Object> &objects)
{
auto result = Validator::Validate(objects);
if (!result.Success) return;
std::unique_ptr<Stream> stream(new TFileStream(path, fsCreate));
JsonSerializer::Serialize(objects, stream);
}
この際のValidationするクラスや、シリアライズするクラスは適当です。
クラスじゃなくてメソッドでもいい。ただこういう呼び出しの組み合わせで機能を実現する、ということです。
ここで説明したいのは、この時、「2回全体の走査が行われる」とかを一切気にしないということです。
されるのが当たり前だと考えているのもあるし、移譲された処理の先で何が起きているか考えること自体が少し違うかなと考えているからです。
それに上記の処理には再利用性があります。
例えば、TCP:IP通信でJson返したいんだよね、とか、WebのレスポンスにJson入れたいんだよね、という時には、ファイルストリームではなく、そちらも大体Stream関連のクラスが用意されているもので、わずかな手間で結果の出力先を変えることができます。
Validation関連の処理は書き込み前にも使えますが、フロントエンドでUI上で簡易なエラー検査処理を行う際にも使えます。(サービスとクライアントが分かれている場合、検査が2回行われるのはありえる。)
fopenの前にやってるobjectsの走査処理と、書き込み操作処理を合わせるというのは、この完全に分割できる二つの処理を、なんとか混ぜあわせて、処理回数を削ろうとしているのに等しいです。
ストリームに一旦書き込めば1個のループに書き込みつつ、ファイルに書き込まないということはできます。しかし、それはつまり書き込む前に一旦メモリに全部書き出すということで今以上にリソースの観点からすればスマートではないやり方になると思います。ストリームがファイルストリームなら結局ファイルができてしまいますし。
ストリームにする最大の利点は、どのストリームに書き込むかを選択できることですからね。
現在言えることは、検査と書き込みを合体することはオススメできません。
いやいや、ものすごくピーキーなんだよ!データ数も物凄い量なんだよ!この処理は!
という時は、異常なデータが作られるのはどこなのか、どこでその間違いを防げるのか、そういうところを探し、そこで検査を行って、書き込み処理に来るデータを正常なものだけになるようにしましょう。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.10%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2017/03/01 13:45
ストリーム処理は経験が少なく調べても使えそうなのが見つからないため、サンプルコードを示していただけないでしょうか?
2017/03/01 14:06
C++対応のライブラリなら、std::ostreamへの出力をサポートしていることが一般的と思うのですが。
もし、お使いのライブラリがRapidJSONでしたら、std::ostreamをサポートしてなさそうですね。
http://qiita.com/k2ymg/items/eef3b15eaa27a89353ab
を見ると、メモリへの出力としてStringBufferStreamをサポートしていると言うことですので、そこへ出力後、その内容を文字列として取り出してファイルへ書き込めば良いと思います。