
fgetsでファイルを一行ずつ読み込みたいのですが、二行目以降が文字化けしてしまいます。
*******
ソース
*******
#include <windows.h>
#include <stdio.h>
FILE *fp;
if ((fp = fopen("textlist.txt", "r")) == NULL){
MessageBox(NULL, TEXT("ファイルを開けません"), NULL, NULL);
exit (1);
}
while (1) {
TCHAR buf[128] = {0};
if (fgets(buf, sizeof(buf), fp) == NULL) break;
MessageBox(NULL,buf,NULL,NULL);
}
fclose(fp);
*****
textlist.txt
*****
あいうえお
かきくけこ
さしすせそ
メッセージボックスの一回目は正しく"あいうえお"と表示されますが、二回目・三回目は文字化けしています。
最終的に一行ずつ分けて配列に入れたいので、fgetsで出来たらと思っています。
よろしくお願いします。
No.6ベストアンサー
- 回答日時:
わかりました。
ちょっと事情があって VC7.1(2003)で試したのですが
2005でも同じだと思います。
MSDNによると
fgets、fgetws (CRT)
http://msdn2.microsoft.com/ja-jp/library/c37dh6k …
fgetws は、ワイド文字引数 str の読み出しを行い、stream がテキスト モードで開かれた場合はマルチバイト文字列として、バイナリ モードで開かれた場合はワイド文字列として読み出します。
とありますので、テキストをUnicodeで書いていたとしても、
if ((fp = fopen("textlist.txt", "r")) == NULL){
のようにテキストモードでオープンしてしまうと、
_fgetts(実体は fgetws)で読み込んだときに自動的に
ShiftJISに変換されてしまいます。
#実際はもうちょっと手が入るようですが
fopen(, "r")/fgets の組み合わせで2行目以降が
化けるのは前回の説明でいいとして、
結局のところ、
"rb" で fopen(もしくは _tfopen)を呼び出し、
fgetws(か _fgetts)で読み込んで
MessageBoxWで表示
のようにしないといけないようです。
#define _UNICODE
#define UNICODE
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#pragma comment(lib, "user32.lib")
int
main()
{
FILE *fp;
if ((fp = _tfopen(TEXT("textlist.txt"), TEXT("rb"))) == NULL){
MessageBox(NULL, TEXT("ファイルを開けません"), NULL, 0);
exit (1);
}
while (1) {
TCHAR buf[128] = {0};
if (_fgetts(buf, sizeof(buf), fp) == NULL)
break;
MessageBox(NULL, buf, NULL, 0);
}
fclose(fp);
return 0;
}
こんな感じのでとりあえず動いているようです。
#ただし あいうえおの前にゴミが出る
テキストファイルの文字コードはメモ帳の Unicode でいいです。
できました!ありがとうございます。
バージョン違いからか、こちらでは前にゴミは出ませんでした^^
何度も回答いただいて、ありがとうございました。
No.5
- 回答日時:
すみません。
見落としと勘違いがありました。
> if (fgets(buf, sizeof(buf), fp) == NULL) break;
のように fgets を使っていますが、これではUnicodeが使われている
テキストファイルを正しく読むことができません。
というのも、行末の改行は(WindowsではLittle EndianのUnicodeなので)
0x0d 0x00 0x0a 0x00 のようになりますが、fgetsはこれがUnicodeであるとは
みなしていないので、0x0a まで読み進めたところで行末を見つけたと
判定してしまいます。
当然次の行は 0x00から始めますので、見事に位置がずれてしまうというわけです。
ファイルの先頭行はこういうずれは決して起きないので、正しく表示されていた。
というわけです。
ということで fgets を _fgetts に置き換えてやればよいのではないでしょうか?
fgets、fgetws (CRT)
http://msdn2.microsoft.com/ja-jp/library/c37dh6k …
この回答への補足
_fgettsにしましたが、最初から文字化けしてしまいました。
テキストファイルをBigEndianにしても、文字化けしました・・
No.4
- 回答日時:
テキストをShiftJISで書いたものにして、
マルチバイト文字環境でコンパイルすると文字化けは起きませんでした。
で、
> テキストファイルはXPのメモ帳でUnicodeで保存。
ということなので、メモ帳で同じようなテキストを作って確認したところ、
00000000: FF FE 42 30 44 30 46 30 48 30 4A 30 0D 00 0A 00 .~B0D0F0H0J0....
00000010: 4B 30 4D 30 4F 30 51 30 53 30 0D 00 0A 00 55 30 K0M0O0Q0S0....U0
00000020: 57 30 59 30 5B 30 5D 30 0D 00 0A 00 W0Y0[0]0....
のようになっています。
多分、MessgeBoxWに渡すテキストには BOMが必要なのに、
ファイルからとってきたテキストでは
ファイルの先頭にしかBOMがないので正しい
Unicodeによる適すとしてみてくれなくて
結果として化けたんじゃないですかね。
メモ帳で、Unicode(Big Endian) でセーブしたテキストだと
どうなりますか?
No.3
- 回答日時:
★コンパイラは何ですか?
・もしも VC++2005 ならばオプション設定で『マルチバイト文字セットを使用する』に
変更してみて下さい。多分、設定のせいです。
理由としてはプログラムが Unicode 文字を扱うように作られていた場合に fgets()
でファイルから読み込むとマルチバイト文字(シフトJIS文字)のために表示がおかしく
なると思います。これはテキストファイルが Unicode 文字ではないからです。
・設定を変更するには構造プロパティを開き→『全般』→『文字セット』の項目を
『マルチ バイト文字セットを使用する』にします。
でもちょっと気になるのが
>メッセージボックスの一回目は正しく"あいうえお"と表示されますが、
>二回目・三回目は文字化けしています。
↑
となっている点です。最初の一回目だけは正しく表示されるのか?不思議?
・あと MessageBox() の第4引数は NULL ではなく MB_OK 定数を使いましょう。
余談:
・fopen() 関数のオープン文字列で『rt』は『rb』に対してテキストモードを指定する
意味ですが昔、聞いた話ではどこかの処理系の拡張指定だったと思います。
なので普段テキストは『r』『w』『a』の指定で良いです。
バイナリは『b』を付けた『rb』『wb』『ab』と指定します。
・以上。
この回答への補足
VC++2005です。マルチバイト文字にすると一回目から文字化けしました。
情報が不足で申し訳ありません。
WindowsXP
Microsoft Visual Studio 2005 Academic Edition
テキストファイルはXPのメモ帳でUnicodeで保存。
プロジェクトオプション "Unicode文字セットを使用する"
ソースファイルの拡張子はcppでなくcにしています。
# fopenはrtにしても変わりませんでした。
# 一回目で文字化けすれば諦めてfgets以外の方法を探すのですが、
# 中途半端に上手くいくばっかりに困ってます・・
No.2
- 回答日時:
他人の回答にケチを付けるのは気が引けますし、禁止事項にも抵触するのでしょうが、放置しているわけにはいかないので指摘します。
> テキストファイルを読み込む場合は「"r"」ではなく「"rt"」で。
上記は嘘です。
> 「"r"」を指定した場合は「処理系依存」なので、もしバイナリで開かれた場合は改行文字が正しく処理できずfgetsは「動作結果は未定義」となります。
そんなことはありません。
むしろ、"rt"を指定した場合の動作が未定義になります。
> ※ライブラリ仕様の「動作結果は未定義」とは「バグるから何が起きるか予想できない」と言う意味です。
何が起きるか予想できないのはある意味その通りですが、必ずしも「バグる」わけではありません。
今回の件に関しては、標準規格でも、("rt"のような規定外の文字列を使用した場合には)「動作は未定義とする」としつつも、処理系は残りの文字の並び(今回でいえば"t")を無視してよいなどの具体例を挙げています。
No.1
- 回答日時:
>fopen("textlist.txt", "r")
テキストファイルを読み込む場合は「"r"」ではなく「"rt"」で。
fopen("textlist.txt", "rt")
「"r"」を指定した場合は「処理系依存」なので、もしバイナリで開かれた場合は改行文字が正しく処理できずfgetsは「動作結果は未定義」となります。
※ライブラリ仕様の「動作結果は未定義」とは「バグるから何が起きるか予想できない」と言う意味です。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
fgetws関数で読み込んだUNICODE文字列の文字化け
C言語・C++・C#
-
fgets で値が取得できない
C言語・C++・C#
-
VC++でUTF-8のファイルを出力したい
C言語・C++・C#
-
-
4
日本語が文字化けしないよう読み込み
PHP
-
5
テキストファイルから読み込んだ文字が文字化けします。
C言語・C++・C#
-
6
fgets関数のEOFの扱い方について
C言語・C++・C#
-
7
<unistd.h>をVisualStudioでつかえるようにする
C言語・C++・C#
-
8
C言語のポインターに関する警告
C言語・C++・C#
-
9
csvファイルをfscanfで読み込むと変な文字が出てきます
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
ファイル内のデータを1行削除...
-
[動的配列]C言語の勉強で簡単な...
-
ファイル読み込みについて
-
c言語 2つのファイルを行ご...
-
VBSで指定行に挿入
-
テキストファイルの行数を取得...
-
C++でのファイル読み書き
-
C言語のローカル変数の使い方に...
-
【VB.Net】バイト型配列に読み...
-
バイナリファイルをテキストフ...
-
【C言語】テキスト読み込みの行...
-
fgetsで2行目から文字化け
-
0x00をファイル出力
-
C言語でファイルから読み込みが...
-
C言語初心者の質問失礼します。
-
どんなプログラムを書いても指...
-
「UNCパスはサポートされません...
-
Access クエリ実行が急に非常に...
-
バッファとは何ですか
-
VB.NETで他のプロジェクトで作...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
バイナリファイルをテキストフ...
-
テキストファイルの行数を取得...
-
ファイル内のデータを1行削除...
-
巨大なテキストファイル(可変...
-
複数テキストファイルを読み込...
-
fgetsで2行目から文字化け
-
【VB.Net】バイト型配列に読み...
-
改行までの一文字ずつのファイ...
-
C言語での改行コードの扱いにつ...
-
InternetReadFileで大きいファ...
-
C/C++ ファイル入出力操作 (長...
-
fopenで開いたファイルのサイズ...
-
fopen(書き込みモード)でファイ...
-
テキストファイルの文字列の削除
-
ファイル読み込みについて
-
C言語のローカル変数の使い方に...
-
freadとfwrite
-
EOF判定されない
-
続・EOF判定されない
-
fortranで文字列を読み込む際の...
おすすめ情報