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

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

新規登録して質問してみよう
ただいま回答率
85.37%
Qt

QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。

C++

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

Q&A

解決済

2回答

4657閲覧

[Qt]テキストファイルの書き込み

BeatStar

総合スコア4962

Qt

QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。

C++

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

0グッド

0クリップ

投稿2018/09/03 02:33

編集2018/09/05 02:07

趣味でC++やっています。Qtについてですが、
テキストファイルの書き込みに関して質問します。( 改行については一応解決したっぽいのでいいですが、後述の「なぜか別のソフトで認識できない」問題が残っています。 それについてです。 )

(※ 長文になります)

C++

1namespace Test{ 2 namepsace TextFile{ 3 void bool write( const QString &filepath, const QString &title ){ 4 QFile file( filepath ); 5 if( !file.open( QIODevice::WriteOnly ) ) return false; 6 QTextStream ts( &file ); 7 ts.setCodec( QTextCodec::codecForName( "UTF-8" ) ); 8 ts << "[INFO]\n\r"; 9 ts << (QString("TITLE=") + title + QString("\n\r")); 10 ts << (QString("TITLE=") + title + QString("\n\r")); 11 file.close(); 12 return true; 13 } 14 } 15} 16 17// 呼び出し元として 18if( Test::TextFile::write( "definition.ini", "あいうえお" ) ) ... // OKなら印字するなりする 19

としました。

で生成されたテキストファイル ( 上記なら iniファイル ) をWindows付属のメモ帳で開くと

本来なら

[INFO] TITLE=あいうえお TITLE=あいうえお

となっているべきですが、なぜか

[INFO]TITLE=あいうえおTITLE=あいうえお

と改行がなされていません。

試した方法1: ts << "[INFO]\n";
試した方法2: ts << "[INFO]" << "\n" << flush;
試した方法3: ts << "[INFO]" << "\n\r" << flush;
試した方法4: ts << "[INFO]\n\r";

...

試した方法5: // file.open( QIODevice::WriteOnly | QIODevice::Text ) で開き、その他の設定は同じとして ts << "TITLE=" << title << "\n";

とやってみると方法1~4はダメでした (結果が最初と同じ)が、
方法5でやってみるとできました。(= メモ帳で開いても改行されていた。 )

ですが、なぜか他のソフト(自分が開発した)では文字化けするみたいです。
メモ帳で開いて何かしらのデータを書き込んで上書き保存をすると普通に使えました。

例えば

オリジナルだと

[INFO] TITLE=hello TITLE=hello

となっているのを"abc"を追加して

[INFO] TITLE=hello TITLE=hello abc

とすると(生成したiniファイルが)普通に使えました。

やろうとしていたことは、

(予定としては)自分用に、ソフトA (自作) を zipファイルに圧縮して ソフトB (自作) に同梱して
ソフトBに情報 ( ファイルの生成場所等 ) をEDITに相当するQLineEditに渡して
ソフトA用のzipファイルをデスクトップ (任意) に解凍して
ソフトA用のiniファイル ( 定義ファイル ) を解凍先と同じディレクトリに生成。
...という風に、ソフトAを使いやすくする感じです。( __生成したいファイルと生成器みたいな感__じでしょうかね。 )

でも方法5だとなぜか文字化けするようで、ソフトAがうまく動かないです。

ソフトAは QSettingsを継承して使いやすくした IniFileHandler::FileReaderクラス (自分用) を使ってiniファイルを読み込みます。
ソフトBは生成器みたいな感じです。

で、悩んだ末、iniファイルとしてQSettingsを使っているのだからQSettingsで書けばいいんじゃないか。
と思い、IniFileHandler::FileReaderの書き込み版である (QSettingsを継承しているものとして) IniFileHandler::FileWriter で書き込んでみました。
すると問題が解決しました。

試した方法6: QSettingを継承したクラスで生成する方法に切り替える

ですが、テキストファイルとして生成したはずの方法5だとテキストファイルとしては認識されていないのか、
ソフトAでは使えなかったのでどうしたものかと...

今回はいいですが、後で、例えばエクセルのために CSVファイルを生成する...のように自分が組んだもの、そうでないもの関係なく、
他のソフトのためにテキストファイル( *.txt )を生成して外部ソフトが読み込めるようにするソフトを作る時とかに
また問題になりそうなので、ここで解決したいなぁと。

要約すれば、「自ソフトだけじゃなくて他のソフトでもテキストファイルとして認識し、使用することができるように生成する方法」です。

今、外出先なのですぐには試せませんが...

[情報]
言語: C++
コンパイラ: MinGW
Qt: Qt 5.6 (LGPL)


[追記及び解決したことを提示]

解決しました。Chironianさんの回答が解決への糸口になったのでChironianさんをBAとするためにここに
解決した方法を書いておきます。( 似たような問題に直面した方のために。 )

私の解決方法は、

C++由来のstd::ofstreamをコンポジションしてクラス化する。
そのクラスは引数としての文字列はQStringで受ける。
メンバ関数やコンストラクタ内で QString -> char* に変換する処理 ( QString -> std::wstring -> std::string -> char* )
をして std::ofstream::operator<< に渡す。

例:

C++

1// MyLib::toString() は QString -> std::wstring -> std::string と変換する関数だとする。 2namespace IoFile{ 3 class FileWriter{ 4 public: 5 FileWriter( const QString &filepath ){ 6 ofs.open( MyLib::toString( filepath.toStdWString() ).c_str() ); 7 } 8 9 ~FileWriter(){ ofs.close(); } 10 11 void write( const QString &text = QString("\n") ){ 12 if( text.compare( "" ) == 0 ){ ofs << endl; return; } 13 ofs << MyLib::toString( text.toStdWString() ).c_str(); 14 } 15 protected: 16 std::ofstream ofs; 17 }; 18} 19 20

C++のSTL使うぐらいならQt側のを使え...って言われるぐらいだから、普通にやり方があるんじゃないかなぁ...と思ったので。
お騒がせしてすみません。

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

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

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

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

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

guest

回答2

0

ベストアンサー

こんにちは。

気にしていなかったのですが、確かに「普通」にQTextStreamを使うと改行がLFのみになっています。CR LFでないためWindowsのメモ帳などで見ると改行がないように見えます。

if( !file.open( QIODevice::WriteOnly ) ) return false;

を以下のようにすればよいはずです。

if( !file.open( QIODevice::WriteOnly | QIODevice::Text ) ) return false;

投稿2018/09/03 03:28

Chironian

総合スコア23272

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

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

BeatStar

2018/09/03 04:26

ご回答ありがとうございます。 すでに方法5で試してみました。 一応改行はなされるのですが、質問でいうソフトB で生成した iniファイル ( QTextStream ) をソフトAで読み込ませると文字化けするみたいです。 質問がわかりにくかったですよね? ちょっと修正します。
Chironian

2018/09/03 06:37

長かったのでちゃんと読んでませんでした。申し訳ない。 さて、このようなケースで良くあるのは、BOMが邪魔していることです。ただ、BOM無し指定を見つけることができませんでした。http://doc.qt.io/qt-5/qtextcodec.html#details QSettingで出力したファイルと、QTextStreamで出力したファイルをバイナリ・レベルで比較するとBOMの有無を確認できる筈です。ファイル先頭の3バイトがBOMです。 BOMがあるとエラーになるソフト(bashなども)も少なくないです。そのようなソフトで使うファイルでワイド文字を使うことを諦めるのも1つでしょう。 他にQTextStreamエンコード無しを指定し、UTF-8への変換は自力で行うなども考えられます。(QStringからならtoUtf8()一発です。)
BeatStar

2018/09/03 06:44

(長文に関してはすみません...) あー、バイナリエディタでチェックかぁ。 デフォルトではBOM付きというやつで、これが邪魔をしていると。 >> 他にQTextStreamエンコード無しを指定し、 今、手元にないので帰宅後試してみますね。
BeatStar

2018/09/05 02:02

帰宅後、試してみました。なるべくUTF-8がいいので >> そのようなソフトで使うファイルでワイド文字を使うことを諦めるのも1つでしょう。 についてはやむを得ない場合にしたいのです。 ( その相手のソフトが指定している場合は仕方ないですが。 ) >> 他にQTextStreamエンコード無しを指定し、... なので質問のやつだと ts.setCodec( QTextCodec::codecForName( "UTF-8" ) ); の部分をコメントアウトしてみて試してみました。 結果は同じでした。(文字化けする...) で、"書き込み=>デフォルト, 読み込み時=>(読み込んだ後に)UTF-8に変換する" という考えから、C++由来 ( STLの std::ofstream等 ) で質問で言えば 引数であるconst QString &title を std::wstring -> std::string にする自作関数 static MyLib::toString() に QString::toStdWString() を渡して std::ofstream ofs( "definition.ini" ); ofs << "TITLE=" << MyLib::toString( title.toStdWString() ) << endl; のようにしてやってみたところ、うまく行きました。 Qtを使っている場合はQt側のQListとかを使え。みたいな記事が多いので、 なんとかQt側で出来ないのかなぁと思ったので質問しました。 一応解決した方法として質問の方に載せておきます。
guest

0

Windowsでの改行は、\r\nです

投稿2018/09/03 02:37

y_waiwai

総合スコア88024

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

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

BeatStar

2018/09/03 04:29

ご回答ありがとうございます。 あー、改行のやつって逆だったんですね...
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問