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

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

新規登録して質問してみよう
ただいま回答率
85.48%
ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

7802閲覧

ベクターのデータをファイル出力

tyapapa

総合スコア51

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/08/18 01:11

編集2020/08/18 02:02

vectorに格納されているデータをすべて
一度のファイル書き込みで出力したいです。
以下の場合だと、期待通りの出力をしてくれません。
(abcdefのみが出力されます。)

C++

1int main() 2{ 3 const char* pstr = "abcdef";  // 配列 4 std::vector<const char*> vstr; // ベクター配列 5 std::fstream outfile; // 出力先のファイル 6 7 for (int i = 0; 6 > i; i++) 8 { 9 // 文字列格納 10 vstr.push_back(pstr); 11 } 12 13 // 正常に格納できているか確認 14 for (const auto& i : vstr) 15 { 16 std::cout << i << std::endl; 17 } 18 19 outfile.open("適切なファイルパス", std::ios::out); 20 outfile.write(vstr[0], (vstr.size() * sizeof(char))); 21} 22

書き出したいイメージ

abcdef
abcdef
abcdef
abcdef
abcdef


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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

うーん、どうしても一度の書き込みにしたいのはなんででしょうかね?一番シンプルなのは一度の書き込みにこだわるのをやめるという選択肢です。それができないというのは、例えばWebDAVとかで物理的に極めて遠い場所をマウントしていてレイテンシーが無視できず、かつ通信量ではなく通信回数で課金額が決まるような場所に書き出すとかそういう話ですかね?そんなのあるのか知らんけど。

そういう場合は一度std::stringstreamに書き出して、その組立てた文字列を取得し、それを書き出すという手段が考えられます。

ただし、上記のような極めて過酷で特殊で存在するかも怪しいような状況が発生していな限り、つまりほとんどすべての状況で速度的にも書くコード量的にも消費メモリー量的にも不利です。こんなコードが必要となる現状そのものをまずはどうにかすることを強く推奨します

もう一度いいますが、無理に一度で書き出そうとすることは速度的にもその他ありとあらゆる観点で不利です

cpp

1#include <cstdio> 2#include <sstream> 3#include <vector> 4int main() 5{ 6 const char* pstr = "abcdef"; // 配列 7 std::vector<const char*> vstr; // ベクター配列 8 9 for (int i = 0; 5 > i; i++) 10 { 11 // 文字列格納 12 vstr.push_back(pstr); 13 } 14 std::stringstream ss; 15 for (const auto& i : vstr) 16 { 17 ss << i << std::endl; 18 } 19 const auto out = ss.str(); 20 const char* out_path = "/path/to/file"; 21 const auto fp = std::fopen(out_path, "wb"); 22 if (nullptr == fp) return 1; 23 std::fwrite(out.data(), out.size(), 1, fp); 24 std::fclose(fp); 25}

本当に大事なことなのでもう一度いいますが、無理に一度で書き出そうとすることは速度的にもその他ありとあらゆる観点で不利です

投稿2020/08/18 04:18

yumetodo

総合スコア5850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

tyapapaさん

std::ofstreamでは<<演算子を
使うと簡潔にかけます。
下記に修正したコード載せときます。

c++

1#include <iostream> 2#include <vector> 3#include <fstream> 4 5int main() 6{ 7 const char* pstr = "abcdef"; // 配列 8 std::vector<const char*> vstr; // ベクター配列 9 std::fstream outfile; // 出力先のファイル 10 11 for (int i = 0; 5 > i; i++) 12 { 13 // 文字列格納 14 vstr.push_back(pstr); 15 } 16 17 // 正常に格納できているか確認 18 for (const auto& i : vstr) 19 { 20 std::cout << i << std::endl; 21 } 22 23 outfile.open("./out.txt", std::ios::out); 24 for(const auto& i:vstr)outfile << i << std::endl; 25 outfile.close(); 26} 27 28

追記

下記解説誤った解説の疑いあり(yumetodoさんより)

writeを用いた
一括書き込みを行うコード

まず私の環境では元コードをコンパイルして
実行するとファイルは生成されましたが
abcdefとしか記載されていませんでした。

その理由は恐らく
元コードではwriteメソッドの第一引数で
vstr[0]を指定しており、
そのvstr[0]はpstrが格納されています。
もっと詳しく説明しますとそのpstrの文字aの番地です。
そしてそのアドレスから6番目のアドレスに終端文字が入っているので
出力されるファイルにはabcdefしか記載されないということです。

そこで下記のようにメモリ上に一列に終端文字を改行コードに置き換えた
メモリを作ることができればwriteメソッドで一括書き換えできるかと思います。

c++

1#include <iostream> 2#include <fstream> 3#include <vector> 4#include <cstring> 5 6int main() 7{ 8 const char* pstr = "abcdef"; 9 10 // もともとpstrの番地を格納したvectorでしたが 11 // a,b,c,d,e,f,\n,a,b,c,d,e,f,\n...と並べたメモリを作成するためchar型を格納するvectorに変更 12 std::vector<char> vstr; 13 std::fstream outfile; 14 15 for (int i = 0; 6 > i; ++i){ 16 for(int j=0; j<std::strlen(pstr); ++j){ 17 vstr.push_back(pstr[j]); 18 } 19 vstr.push_back('\n'); 20 } 21 22 for (const auto& i : vstr)std::cout << i ; 23 24 outfile.open("./out.txt", std::ios::out); 25 outfile.write(&vstr[0], vstr.size());//一括書き込み 26} 27

投稿2020/08/18 01:38

編集2020/08/18 05:53
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2020/08/18 01:40

writeを使いたいらしいです.
tyapapa

2020/08/18 01:51

回答ありがとうございます。 forによって何度もファイル書き込みを行っておりますが、 一度の書き込みでvectorの中身を出力する方法はないでしょうか。
退会済みユーザー

退会済みユーザー

2020/08/18 04:13

fanaさん tyapapaさん お返事有難うございます。 よく見ずに回答してしまい失礼しました。 writeで一括書き込みできるコードを 回答欄に追記しておきます。
yumetodo

2020/08/18 05:26 編集

そもそも論なんですけど、basic_fstreamのwriteって本当に1回の書き出しになりましたっけ?streambufの仕様上、std::streambuf::sputnはvirtual int_type overflow(int_type _Meta = Traits::eof())を各文字について呼び出すと記憶しています。std::file_bufのoverflow実装がvirtual int sync()が呼ばれるまでバッファリングする実装になっていて、かつwriteの途中でsyncが呼ばれないならば一気に書き出せるかもしれませんが・・・。
退会済みユーザー

退会済みユーザー

2020/08/18 05:45 編集

yumetodoさん ご質問有難うございます。 恐らく私の追記内容に問題がある部分をご指摘頂いているのかと思われますが 知識不足でご質問の内容がよくわかりませんでした もう少しわかり易くどのあたりがおかしいのか 教えていただけたら誤った記載を修正できるので とてもありがたいです。 どうか御返事お待ちしております。
yumetodo

2020/08/18 06:02

シンプルに要約すると、std::basic_ostream::writeの呼び出しは質問者の要求である「一度のファイル書き込みで出力」を満たすか、ですね。 御存知の通りiostream系クラスは内部でバッファリングがなされます。std::basic_streambufがこのバッファリングを担当するクラスの基底クラスとなります。この基底クラスにはいくつかにprotectedなvirtualメンバ関数があり、これをoverrideすることでポリモフィズムを実現しています。overflowやsyncもそういったproteced virtual member functionに一つです。 overflowはsputc/sputnというpublic member functionから呼び出されます。関数の引数から明らかなようにこの関数は1文字しか受け取りません。
yumetodo

2020/08/18 06:05

つまり一番シンプルな実装として1文字ずつ書き出す実装があり得るのではないかということです。規格書でなにか禁じているような文面があるかどうか確認していない段階の発言ですが。
退会済みユーザー

退会済みユーザー

2020/08/18 07:19 編集

yumetodoさん お返事誠にありがとうございます。 貴方の記載して下さったリンクと 下記リンクを参考になぜ一括ではストリームへ送信できないのか 調べてみました。 自分の解釈が正しいか確認をよろしくお願いいたします。 https://docs.microsoft.com/ja-jp/cpp/standard-library/basic-streambuf-class?view=vs-2019 にbasic_streambuf::sputcはストリームに1文字渡すメソッドであり sputnはストリームに文字列を渡すメソッドである。 と書かれている事から sputcの場合は1文字づつストリームへ渡しているので一括ではないことが分かる。 sputnの場合 https://clown.cube-soft.jp/entry/20080714/p1 に書いてあるように間接的にsputscが引数のn回呼ばれているだけなので どちらにせよ一括で出力ストリームにメモリの情報を送信することはできないとyumetodoさんは推測している。 こんな感じの解釈でよろしいでしょうか。 また、まだ私はstd::basic_streambufを使ったことがない(意識したこともなかった) のでとても勉強になりました。 ありがとうございます。 以上どうか御返事お待ちしております。
yumetodo

2020/08/18 10:52 編集

いや、std::file_bufがsputcで書き込み動作をせずにpubsyncした段階で(=flushしたときに)書き込んでいるなら大丈夫ですが、例えば一定以上溜まったら強制的に吐き出すとかそういう実装はあり得ると思ったもので。 あるいはxsputnをfile_bufがoevrrideしていて、xsputnが呼ばれればバッファリングをしなくても直接書き出せるかもしれませんが前に試したときMSVCの実装からはxsputnが呼ばれなかった気がするんですよね。
退会済みユーザー

退会済みユーザー

2020/08/18 17:13

yumetodoさん お返事誠にありがとうございます。 理解しようといろいろ調べてみましたが 今の所よくわからないままです。 今後std::basic_treambufを使い始めたら わかってくるかもしれません。 解決済み解答欄で私からstd::basic_treambufにまつわる質問 するのもどうかと思うのでこれ以上のやり取りは 控えさせてもらいますが とても親身に教えて下さり感謝申し上げます。 あと tyapapaさん 誤っているであろう解説をしてしまい 大変失礼いたしました。 私の回答の追記内の打ち消し線は そのままとさせていただきます。
guest

0

ベストアンサー

outfile.write((char*)&vstr[0], (vstr.size() * sizeof(char)));

書いていることが滅茶苦茶であると見える.
vstrの要素の型は何か?等を鑑みて,このコードが何をしようとしているのかを考えてみてはどうか.

投稿2020/08/18 01:28

fana

総合スコア11658

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2020/08/18 01:30

(coutと同様の手段でファイル出力するのではダメな場面(?)なのであろうか…?)
tyapapa

2020/08/18 01:32

既にchar*型のものをcastする必要なかったですね。。 writeを使用した方法を知りたいです。
fana

2020/08/18 01:37

まずwriteで単一の文字列を出力するところからやってみては? →それができるのならば,それをvectorの要素数だけ繰り返せばよいのでは.
tyapapa

2020/08/18 01:50

繰り返しをする場合、何度もファイルに書き込みを行うわけですよね? そうではなく、一度でvectorの中身をすべて書き込めるようにしたいです。 その場合だとwriteを使うしかないのかなと考えてました。
fana

2020/08/18 02:24 編集

他の回答へのコメントにも書きましたが… > vectorの中身 って一体何ですか(何だと思ってますか)? っていう話. vstrの個々の要素はポインタなのであり,それらは「どこぞに存在する文字列の先頭要素の存在箇所を指し示す何らかの値」である. vstr自体は「文字列」を保持していない. 「一度で…」とかいう要望は, 例えるならば, const char *pA = "Hello"; const char* pB = "Cat"; const char* pC = "Kitten"; なる複数個の「文字列の先頭を指すポインタ」が存在する場合に,【"Hello"と"Cat"と"Kitten"を一度のwriteでファイルに書きたい】と言っているようなもの. 一度のwriteで済ませるためには,これらの文字列を連結するなりして「連続した一つの文字列」みたいなデータを作らねばならないだろう. あと,実際に「何度もファイルに書込みを行う」ことになるかどうか(:write毎にファイル書込みが発生するかどうか)はわからない:相応にバッファリングされるのではなかろうかと思う. 何かそうすべき特別な理由が無いならば,「一度に…」に過度に拘る必要はないと思うが,どうか. (というか,そんなところにこだわるよりも前に,まずはご自身が書いているコードの意味を把握すること(というか把握してコードを書くこと)に努めた方がよろしかろう,と思う)
fana

2020/08/18 02:22

> 他の回答へのコメントにも書きましたが… って書いたら,その回答が消えている.何だ…?
tyapapa

2020/08/18 09:14

連結させて出力してしまえばよかったんですね。ありがとうございます。 回答が消えた理由はわかりません。
fana

2020/08/18 09:20

「writeの呼び出しを1回にするには」出力するイメージをメモリ上で連続したデータとして用意する必要がある. しかし,それとは別に「ファイルへの書込み処理が発生する回数」に関しては,バッファリング等が関係してくるでしょうから,「writeの呼び出しを1回にする」ことに実際上どれだけの意味があるのかは謎です.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問