• ベストアンサー

ファイルの読み取りについて

現在C言語の勉強中ですが、 テキストファイルがあったとします。 ファイル内容 abc ,111 def ,222 ghi ,333 っとあったとします。 プログラムで入力した数値で、どの行番号のどのブロックの 文字列を取得し表示したいのですが、行とブロックの指定方法が わからなくて困っています。 ご回答よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.4

★もう一つアドバイスします。 ・回答者 No.2 さんの補足で実行速度を削りたくないようならば、1行のデータを  固定長のデータとします。つまり、『x,y,w,h』を2桁(3桁)のカンマ区切りのデータ  とするのです。 データ例: //x, y , w , h ←実際には記述しない(記述すると計算式を調整する必要がある) 000,000,050,050 000,000,050,050 000,000,050,050 000,000,050,050    : 高速に: ・上記のデータ例のように固定長のデータにすれば、次の計算式でランダムアクセスを行えます。  計算式⇒『(行番号×17)+(列番号×4)』⇒ランダムアクセスするオフセット位置になる。 ・上の計算式の『行番号』、『列番号』ともに『0』から始まる数値です。  つまり、1段目のデータ行が『行番号』で『0』、2段目のデータ行が『1』を表す。  同様に1列目のカンマ数値が『列番号』で『0』、2列目のカンマ数値が『1』を表す。 ・オフセット位置が計算できたらば『fread』関数で 17 バイトを読み込む。  char buff[ 32 ];  int x, y, w, h;    fseek( fp, ((行) * 17L + (列) * 4L), SEEK_SET ); ←オフセット位置に移動    if ( fread(buff,sizeof(char),sizeof(buff),fp) == sizeof(buff) ){   x = atoi( buff + 0 * 4 ); ←座標を数値に変換   y = atoi( buff + 1 * 4 );   w = atoi( buff + 2 * 4 );   h = atoi( buff + 3 * 4 );  }  else{   エラー処理  } 最後に: ・上記の計算式の 17 とは1行データの『000,000,050,050』が 15 バイト+『\r』『\n』の 2 バイトで  17 バイトとなるのです。カンマ区切りの1データの桁数を変更するときは計算式も変更して下さい。  たとえば、上記ではすべて 3 桁で記述するようにしていますが、4 桁で記述するように変更すると  計算式は『(行) * 21L + (列) * 5L』となります。→分かりますよね。 ・以上。おわり。→データファイルのオープンは『バイナリ形式』にしましょう。

koedame
質問者

補足

ご回答感謝します。 私が求めていた答えだと思います。ありがとうございます。 最後にどうしてバイナリ形式のファイルオープンなのか知りたいです。 普通のテキスト形式では駄目なのでしょうか?

その他の回答 (4)

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.5

★改行コードの扱いでバイナリの方が良いと薦めたのです。 ・『fseek』関数を『SEEK_SET』定数で使っているので今回の場合は、本当は  テキストモードでもバイナリモードでも両方とも正しく動きます。 ・それで『fseek』関数に『SEEK_CUR』定数や『SEEK_END』定数を使ったとき、  テキストモードだと『\r\n』が『\n』の1つの変換されて『fgets』などでは  返されますよね。この返された文字列長を単純に『strlen』で加算してオフセット値  を管理していると『SEEK_CUR』定数や『SEEK_END』定数のときにバイト数が  ずれるのです。このことから、バイナリモードにすれば『\r\n』はそのまま  2バイトで管理されますのでずれないという理由からです。 ・今後、テキストモードで『fseek』関数を『SEEK_CUR』や『SEEK_END』定数で  ファイルポインタを移動するときは注意して下さい。 ・以上。おわり。→結論、今回はどちらのモードでも良いです。

koedame
質問者

お礼

なるほど、何度もありがとうございます。 とても勉強になりました。 本当にありがとうございます。

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.3

★ブロックとはカンマで区切られたデータのことですか? ・プログラムで入力した数値がデータの数値ならば、1行ずつ読み込んでカンマ区切りの  データと比較します。そして、見つかった行を表示しますが、行番号も一緒に表示するには  1行ずつ読み込むときにカウンタで行数を同時に数えておけば良いでしょう。 ・カンマ区切りのデータは『strchr』や『strpbrk』でカンマ文字を検索して見つかった位置に  NULL 文字をセットします。これで1つ1つのデータを分割できます。あと『strtok』関数でも  分割できます。 ・下にカンマ区切りのデータを分割するサンプルを載せておきます。 サンプル: char buff[ 256 ]; char *token[ 100 ]; ←カンマ区切りのデータ(ポインタへの配列) char *find; char **seek; while ( fgets(buff,sizeof(buff),fp) != NULL ){ ←『fp』がファイルポインタ  seek = token;  *seek++ = find = buff;    while ( (find = strchr(find,',')) != NULL ){   *find++ = '\0';   *seek++ = find;  }  *seek = NULL;  /*  『token』の[0]~[n]にカンマ区切りのデータが分割セットされる  ここで入力された数値などと比較を行います。  token[0] 1つ目のデータ  token[1] 2つ目のデータ  token[2] 3つ目のデータ   :  token[n] 最後のデータ  token[n+1] NULL  */ } 最後に: ・『ブロック』の意味やどんな文字列を取得して表示したいのですか?  イマイチよく分かりませんが、行単位でデータブロックを読み込んで数値文字列と比較などを行って下さい。 ・以上。おわり。

koedame
質問者

お礼

補足に関しては先にご回答いただいた方と同じです。 『strchr』や『strpbrk』に関しては全然知りませんでしたし、 私が考えているプログラムにおいて恐らく使えそうです。 感謝します。_(__)_

  • noro6677
  • ベストアンサー率21% (34/158)
回答No.2

行に関してはループで行数をカウントすれば良いだけだし ブロックとは? abc ,111とあった場合のabcと111を別々のブロックと言うこと? だったら簡単なのは「,」で文字列を分解すること。

koedame
質問者

補足

ご回答ありがとうございます。 実は私はゲームプログラムを勉強しているものですが、 画像ファイルのアイコンの位置情報を テキストファイルにスクリプトとして組もうとしているのですが、 ファイル内容としては以下のようになります。 // x,y, w, h   0,0,50,50   0,0,50,50   0,0,50,50   0,0,50,50     ・     ・     ・ x,y は画像ファイル内での左上の位置 w,h はそのアイコンの幅と高さです。 ブロックとは言い換えれば列です。(すみません、なんでブロックって記述してしまったのか(f^^)) x,y,w,h がブロックに当たります。 他のテキストファイルから読み込んだ値を使って、 つまり行番号を取得して、 その取得した行番号を使ってダイレクトにその行のデータを 取得し、その行のアイコン情報をブロックごと取得し、 他の変数に格納したいわけです。 for文など使い実行速度を削りたくないのです。 すみません長くなって。

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.1

質問の内容があやふやで答えるのが難しいので補足をお願いします。 「プログラムで入力された数値」とはファイルの行番号ということでよいのでしょうか? だとして、「ブロック」というのは何を指して云っているのですか? 「行とブロックの指定方法がわからない」ということですが、 たとえばWindowsプログラムのように入力のダイアログボックスを開きたいとか、 コマンドプロンプトから起動していて、 行番号を入力してください > のようなメッセージを出して入力待ちにすることがわからないということでしょうか? ここでも「ブロック」が登場していますが、具体的にどういうものが ブロックなのかを明示してください。

koedame
質問者

補足

実際は下のように入力を待って取得した二つの値から行とブロックを 指定するのです。 main() {   int nBox[2];   scanf( "%d", &nBox[ 0 ] );//行   scanf( "%d", &nBox[ 1 ] );//ブロック /* この辺でその取得した値を用いて データを表示したいのです。 */   return 0; } 下の例だと縦が行で横がブロックです。 abc ,111 def ,222 ghi ,333 最後になりましたが質問の内容が足りなかったことにお詫びします。

関連するQ&A

  • perlでのcsv形式のテキストファイルの変換

    perlを使用してcsv形式のテキストファイルを下記のように変換したいと思っています。 【変換前】 10, abc , def , ghi ,jkl    ----1行目 10, abc , def , aaa, bbb   ----2行目 10, abc , def , ccc , ddd  ----3行目 11, abc , def , eee , fff   ----4行目 11, abc , def , aaa , ggg ----5行目 11, zzz , def , aaa , ggg  ----6行目 12, abc , def , aaa ,ggg ----7行目 12, zzz , def, aaa , ggg   ----8行目 【変換後】 10, abc , def , ghi ,jkl    ----1行目 11, abc , def , eee , fff   ----4行目 11, zzz , def , aaa , ggg  ----6行目 12, abc , def , aaa ,ggg ----7行目 12, zzz , def, aaa , ggg   ----8行目 変換内容はcsv形式のテキストファイルで、”,”で区切った先頭3列が 前の行の先頭3列と同じならその行は出力しない、といった 変換をしたいと思っております。 (例えば2行目ですと先頭3列は10, abc ,defになっており、  1行目の先頭3列と同じ文字列になっているためこの行は出力しない) 当方、Perl初心者で上記のようなことがPerlでできるかも よくわかっておりません。 そこで、上記のような変換はPerlで可能なのか、そしてもし可能であるのなら どのようにPerlで記述すればできるのか教えていただけないでしょうか。 よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • Excel VBAでの固定長のテキストファイル読み込み

    こんにちは。 会社にてEXCELをちょろっとかじっていると言う理由から、あまり触ったことのないVBAを使って固定長のテキストファイルを読み込むプログラムを作るように言われてしまって困っています。 利用している固定長のテキストファイル中の各行の桁数は同一でなく、行によってまちまち。しかし、各行の始めの3ケタはヘッダになっています。 例) ABCTTTTTTTTTTTTTTTTKKKKKOOOOOOPPPPPPPPWWWWWWWWWWWWWWWWWWWWWWWSS XYZLLLLL <ABCとXYZがヘッダ。同じ文字が固定長で決まったあるデータ項目と考えて下さい> もちろん、1ファイルにはもっとたくさんの行がずらずら並んでおります。 中身自体は、ある伝票の内容なのですが、1ファイル中には複数の伝票内容(ヘッダABC~XYZで1伝票)が記されております。 なので、ヘッダで言うとABC,DEF,GHI...XYZとなってまたABC~が続く。 しかも、ある伝票では途中存在しないヘッダがあったり、同じヘッダが何回も繰り返されたりするものもあります。 (ABC,DEF,DEF,DEF,GHI..やABC,GHI,JKL..など) これをどうやってEXCELの各セルに貼り付けるかがどう頑張っても分かりません。どうすればよいのでしょうか?

  • データをブロックごとに並べ替えるスクリプト

    データをブロックごとに移動して並べ替えたいのですが、 うまくいくスクリプトが書けず困っています。 APR_A----- abc 1 def 2 APR_B----- abc 3 def 4 APR_C----- abc 5 def 6 APR_A----- ghi 1 jkl 2 mno 3 APR_B----- ghi 4 jkl 5 mno 6 APR_C----- ghi 7 jkl 8 mno 9 のようなフォーマットのデータがあります。 これを以下のようにフォーマットを変えたいのですが、 awkを使ってどのようにスクリプトを書いたらよいでしょうか。 元データの中で、区切りの行は常にAPR_で始まっています。 APR_で始まる行に来たら次の列に移って2列目のみprint というのを繰り返し、APR_Aに戻ってきたら、 1列目(abc,defなど)、2列目ともprintして同様に繰り返す。 各ブロックの行数はまちまちです。(最初のブロックのように2行のブロックもあれば2番目のブロックのように3行のもあります) rowtitle APR_A APR_B APR_C abc 1 3 5 def 2 4 6 ghi 1 4 7 jkl 2 5 8 mno 3 6 9 分かりにくい文章ですが、理解していただけることを願っています。 よろしくお願いします。

  • bashスクリプトでのテキストの検索・置換について

    下記のような形式のテキストファイルがあります。 []で囲まれた部分の文字列(セクション名)はわかっています。 各セクションの間には空行があることもあれば無いこともあります。 各セクションの記載順序は不定です。 各セクションの中の記載順も不定です。 各セクションの中の行数も不定です。 別々のセクションに同じ行があり得ます。 この場合に、bashスクリプトの中で、[def]セクションの文字列cccをccdに置き換えるにはどのような方法があるでしょうか。 awkでできるような気がするのですが、 awk '/\[def\]/{BEGINNUM = NR}' FILENAME とすれば BEGINNUM にセクションの始まりを取得できるものの、セクションの終わりの行番号の取得がわかりません。 [def]行の後に最初に出てくる[]の付いた行を検出すればよいのですが、特定の行以降で最初に出てくる文字列の行を検索するのはどうすればよいでしょうか。 あるいは、まったく異なった方法があるでしょうか。 (対象テキストファイル) [abc] aaa bbb ccc [def] aaa ccc bbb ddd [ghi] aaa eee bbb ccc (テキストファイル終了) 2007年3月25日

  • TCHAR文字列内の検索について

    TCHAR文字列内の検索について 質問があります。 #include <tchar.h> TCHAR tex1[8]; TCHAR tex2[8]; TCHAR tex3[8]; TCHAR buf[128] = TEXT("abc,def,ghi"); TCHAR型で宣言された変数bufには、「abc,def,ghi」が格納されているとして、 結果的に tex1 → "abc" tex2 → "def" tex3 → "ghi" となるようなプログラムを作ろうと考えています。(buf内をコンマで区切って3つの変数に代入) まずコンマの位置が何文字目にあるか確認するために TCHAR ret[128]; TCHAR search[128] = TEXT(","); ret = _tcschr( buf, search); としてみましたが、やはりうまくいかずにエラーが出ます。 上記の目的を達成するにはどのようなプログラムを作ればよいのでしょうか? 環境はVisual C++ 2008 Expressで、C言語を使ってプログラミングしています。

  • こんにちは。

    こんにちは。 会社にてEXCELをちょろっとかじっていると言う理由から、あまり触ったことのないVBAを使って固定長のテキストファイルを読み込むプログラムを作るように言われてしまって困っています。 利用している固定長のテキストファイル中の各行の桁数は同一でなく、行によってまちまち。しかし、各行の始めの3ケタはヘッダになっています。 例) ABCTTTTTTTTTTTTTTTTKKKKKOOOOOOPPPPPPPPWWWWWWWWWWWWWWWWWWWWWWWSS XYZLLLLL <ABCとXYZがヘッダ。同じ文字が固定長で決まったあるデータ項目と考えて下さい> もちろん、1ファイルにはもっとたくさんの行がずらずら並んでおります。 中身自体は、ある伝票の内容なのですが、1ファイル中には複数の伝票内容(ヘッダABC~XYZで1伝票)が記されております。 なので、ヘッダで言うとABC,DEF,GHI...XYZとなってまたABC~が続く。 しかも、ある伝票では途中存在しないヘッダがあったり、同じヘッダが何回も繰り返されたりするものもあります。 (ABC,DEF,DEF,DEF,GHI..やABC,GHI,JKL..など) これをどうやってEXCELの各セルに貼り付けるかがどう頑張っても分かりません。どうすればよいのでしょうか?

  • Excelのvlookupの列番号を複数取得したい

    以下のような表1のデータがあります。 vlookupを使用して、表2から2列目以降のデータを引っ張ってきます。 このとき、vlookupの列番号に2を指定すれば、"ABC"が、3を指定すれば"100"が取得できます。 いつもは、列の数だけvlookupを書いて、それを下にコピーしています。 無駄なことやっているような気がしますが、できるだけシンプルに手順少なくできないでしょうか? ■表1 [大阪] [福岡] ■表2 [東京][ABC][100][あああ]・・・・・・・・・・・・・・ [大阪][DEF][200][いいい]・・・・・・・・・・・・・・ [福岡][GHI][300][ううう]・・・・・・・・・・・・・・ ■結果 [大阪][DEF][200][いいい]・・・・・・・・・・・・・・ [福岡][GHI][300][ううう]・・・・・・・・・・・・・・ 以上、よろしくお願いします。

  • 「マッチしない」正規表現の書き方

    正規表現について、おたずねします。 文字列 abc,def,ghi のいずれかにマッチする正規表現は (abc|def|ghi) ですよね。 それでは、「abc,def,ghi のいずれにもマッチしない」正規表現は、どう書けばいいのでしょうか? あちこち調べましたが、どうしてもわかりません。 ただし、if $a =~ /(abc|def|ghi)/ などで、=~ を !~ に直す、というのはナシです。あくまでも右辺の式の中で表現したいのですが…

  • ファイルを開かずにテキストファイルの文字列置換

    続けての投稿で申し訳ないのですが、複数のフォルダ中のテキストファイルすべての中身を検索してある文字列を置換する方法を教えてください。 行いたい作業例ですが、 1)ABC- → ABC-   ある特定の半角文字列+"-"を全角に変換 2)2ー → 2-      ある特定の文字列+"ー(全角の長音)"を文字列+"-(全角のマイナス)"に 3)192.168.0.?? → ABC0?? にしたいです。 フォルダは複数あるため、一階層上から作業できる方がいいです。 AAAというフォルダ下に先のABCというフォルダ以外にDEFやGHIといったフォルダがあり、その下に001-00.txtや001-01.txtというフォルダがあるということです。 よろしくお願いします。

  • 2つのテーブルの連動

    MySQL3を使っています。 [tableA] ID |NUM ------- abc|1 def|2 ghi|3 [tableB] ID |TEXT ------- def|あいうえお abc|かきくけこ def|さしすせそ のような2つのテーブルがあって、[tableB]のデータを[tableA]のNUM列の番号順に、出力するにはどうすればいいのでしょうか? 上の例で行くと、 abc|かきくけこ def|あいうえお def|さしすせそ こんな感じの並びにしたいのです。

    • ベストアンサー
    • MySQL

専門家に質問してみよう