こんにちは。
回答お願いします。
今私は作業の高効率化を目指すためプログラムを考えています。
まだぜんぜんできていませんが・・
ファイルの指定された行を表示する関数がないだろうか?
もしくは似たような方法はないだろうかと考えています。
できれば例題とともに教えていただければ幸いです。
具体的にどういう風にしたいのかというと
----test.txt-------
aaaa
bbbbb
cccccc
dddd
eeeeeeee
ffffff
-------------------
というファイルがあったとしたらgetsで4と入れてやったら
四行目のddddが表示されるようにしたいのです。
まだまだ初心者ですのでさっと考えることができません。
どうかご教授お願いします。
No.1ベストアンサー
- 回答日時:
★高効率を目指しているの?
・固定長データなら高効率で1行を取得できたりします。
例えば
----test.txt-------
aaaaa
bbbbb
ccccc
ddddd
eeeee
fffff
-------------------
という固定長データ(5文字×6行)の場合は
int no = 4; ←4行目を取得したい時
fseek( fp, ((no - 1) * 7), SEEK_SET ); ←5文字+\r+\n=『7』
fgets( buff, sizeof(buff), fp );
↑
これなら行番号で指定した1行を fgets() 関数で取得可能です。
※なおバイナリモードでオープンして下さい。
・可変長データの場合は行の先頭のオフセット位置を最初の読み込みで管理します。
例えば
----test.txt-------
aaaa
bbbbb
cccccc
dddd
eeeeeeee
ffffff
-------------------
という可変長データ(4,5,6,4,8,6文字)の場合は
オフセット位置の配列を行数分用意します。→事前に分かれば楽ですね。行数。
long offset[ 100 ]; ←100行だと仮定
int max;
for ( max = 0 ; !feof(fp) ; max++ ){
if ( max >= 100 ){ ←安全対策
break;
}
offset[ max ] = ftell( fp );
fgets( buff, sizeof(buff), fp );
}
↑
ここまでがオフセット位置の読み込みです。次は読み出しです。
int no = 4; ←4行目を取得したい時
fseek( fp, offset[no - 1], SEEK_SET );
fgets( buff, sizeof(buff), fp );
↑
これで行番号で指定した1行を fgets() 関数で取得可能です。
※やっぱりバイナリモードでオープンして下さい。
・あと行数の指定時に 1~max の範囲になるように補正処理も入れたほうが良いかも。
例えば
if ( no < 1 ){
no = 1;
}
else if ( no >= max ){
no = max;
}
↑
こんな感じで。
・以上を参考にして下さい。
下の『参考URL』もどうぞ。
参考URL:http://www9.plala.or.jp/sgwr-t/lib/fseek.html
回答ありがとうございます。
よくわかりました。
行数が不明な場合
while(fgets(buff, STRING_MAX, filep) != NULL){ /* 1行読み込み */
count++; /* 行数カウント */
}
見たいな感じでカウントしてやって
long offset[ count ];
って感じで宣言できませんかね・・
手元にコンパイラ入ったPCがないもので・・
今日戻ったら試してみようと思います。
No.3
- 回答日時:
★回答者 No.1 です。
行数を最初に数えるの?>行数が不明な場合
↑
最初に行数を数えると巨大な(行数が多い)ファイルだと初期化に時間がかかります。
でも一度、読み込んでしまえば後は行数指定で行を取得できますね。
>long offset[ count ];
>って感じで宣言できませんかね・・
↑
C99 に対応していれば可能です。
既に回答者 No.2 さんのアドバイスにあるとおりです。
余談:
・この質問はどんな処理に利用するのでしょうか?
昔、MS-DOS 時代の時にページャソフト(テキスト・ビューワ)を作ったときに同じ考えで
行の先頭オフセット位置を管理して表示、ジャンプさせました。
あの時代はメモリが少なく、また実行時のメモリを抑えるためにスモールモデルや
タイニーモデルで作りました。
・タイニーモデルでは全体で 64KB に制限されるためオフセット位置のメモリ(配列)を
工夫しました。具体的には 100行単位でのオフセットを記憶・管理します。
その後 123 行から表示をする場合は 100行目の位置へ移動してそこから 199行までの
行の先頭オフセット位置を読み込みます。そして 123 行からの表示をさせました。
・こんな工夫のお陰か巨大な(行数の多い)ファイルでも一度オフセット位置を読み込めば
任意の位置からジャンプして表示するのにあまり時間がかかりませんでした。
でも決して高速表示ではありませんよ。
メモリを節約して行数の多いファイルも閲覧出来ることを目的としていますので。
最大 100,000 行まで覗けました。100行単位に分割しているのがミソです。
動的確保:
・C99 に対応していないと動的確保になりますが、このときに行とオフセット位置の
読み込みを同時にした方が良いでしょう。もちろん最初に行数を単純にカウントしてから
動的に確保しても良いですが。その方が簡単ですしね。
・でも同時にする場合は1024行単位でオフセット位置配列をリスト構造で用意します。
つまり、
typedef struct offset_t {
long offset[ 1024 ];
struct offset_t *next;
} offset_t;
という構造体を用意して
static struct {
struct offset_t *head; // 単方向リストの先頭
struct offset_t *tail; // 単方向リストの最後
struct offset_t **table; // 1024行単位の配列(これが参照用テーブル)
int maxBlock; // 確保したブロック数
int maxCount; // 読み込んだ最大行数
} sys;
という構造体で管理します。
・上記の構造体を使って最初 1024 行まで読み込みます。同時にオフセット位置もセット。
そして 1024 行を超える場合は新しく struct offset_t 構造体を動的確保して鎖のように
つなげていきます。これをファイルの最後まで 1024 行単位で繰り返します。
・すべてオフセット位置を読み込んだ後は maxCount / 1024 のブロック数のポインタ配列を
動的に確保します。→struct offset_t 型の配列
確保したらそのポインタ配列 table[0]~table[maxBlock - 1] に単方向リストの先頭 head
から順に struct offset_t 型のポインタをセットしていきます。
これで
table[0]…0~1023行のオフセット
table[1]…1024~2047行のオフセット
table[2]…2048~3071行のオフセット
:
という感じになります。
※maxBlock は (maxCount / 1024) + !!(maxCount % 1024) という数です。
※maxBlock は (maxCount >> 10) + !!(maxCount & 0x3FF) と計算しても良い。
・指定行のジャンプ・取得では
int no = 12345; ←12345行目を取得したい時
no--; ←行数を 0~??? にするためデクリメント
fseek( fp, sys.table[no >> 10].offset[no & 0x3FF], SEEK_SET );
fgets( buff, sizeof(buff), fp );
という感じで取得できます。
※1024 行単位にしている理由はビットシフト、ビットAND でアクセスするためです。
・あと一度 table を確保したらそのポインタ配列(ブロック数)を maxBlock で管理して
別ファイルを再読み込みする場合に maxBlock 以下ならそのまま、maxBlock 以上になったら
拡張するため table を realloc または free/malloc して下さい。
その他、C++ の Vector などで管理するのも良い。C 言語ならリストで実装するなど工夫。
・以上。参考に。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) エクセルのマクロについて教えてください。 1 2023/08/03 12:30
- Visual Basic(VBA) エクセルのマクロについて教えてください。 1 2023/08/03 11:27
- その他(IT・Webサービス) ホームページにカウント数を表示する 2 2022/10/28 10:37
- Excel(エクセル) 【マクロ】マクロが保存されているエクセルとは、別のエクセルブックの全シートの非表示列を再表示したい 1 2022/12/24 20:48
- CAD・DTP Autocad Scriptファイルからの入力とコマンドラインからの入力が違う 1 2023/08/01 09:13
- Visual Basic(VBA) エクセルのマクロについて教えてください。 1 2023/03/07 14:05
- Excel(エクセル) ワードのマクロについて教えてください。 1 2023/03/11 13:50
- Visual Basic(VBA) 動かなくなってしまった古いVBAを動くようにしたい 8 2022/09/20 13:57
- C言語・C++・C# exeファイルが作れない(windows10) 6 2022/08/13 08:47
- PowerPoint(パワーポイント) エクセルのマクロについて教えてください。 1 2023/01/20 14:36
このQ&Aを見た人はこんなQ&Aも見ています
-
「環境が人を育てる」って本当?環境によって人格や生き方は本当に変わるのか
環境が人生に与える影響は実際どれほどのものなのか、専門家の田宮由美さんに伺った。
-
C言語で複数列のデータを1列のみ読み込みたい
C言語・C++・C#
-
C言語で特定の行を抽出する方法を教えてください。
C言語・C++・C#
-
c言語でのfscanfについて
C言語・C++・C#
-
-
4
ファイル書込みで一行もしくは部分的に上書きする
PHP
-
5
C++でのテキストファイル読み込みの行指定について
C言語・C++・C#
-
6
C言語で特定列だけを抽出して配列に格納し、出力したいです。 読み込みファイル(read.txt) 0
C言語・C++・C#
-
7
C言語 配列の長さの上限
C言語・C++・C#
-
8
特定の文字列が一致する行から、文字列を抽出する方法
C言語・C++・C#
-
9
C言語初心者の質問失礼します。
C言語・C++・C#
-
10
構造体のメンバをfor文で回したい
C言語・C++・C#
-
11
配列の要素数に変数を入れたいときには
C言語・C++・C#
-
12
fgetsなどのときのstdinのバッファを消すには?
C言語・C++・C#
-
13
scanf が無視されます
C言語・C++・C#
-
14
ファイルから読みこむ方法
C言語・C++・C#
-
15
char*を初期化したいのですが
C言語・C++・C#
-
16
C言語 exitの使い方
C言語・C++・C#
-
17
ファイル出力で改行を入れたい!
C言語・C++・C#
-
18
ファイルの途中に文字列を挿入
C言語・C++・C#
-
19
system関数がうまくいかない
C言語・C++・C#
-
20
fprintfで文字化け
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
関数から配列を返すには?
-
C言語において、 配列要素をひ...
-
配列の要素数に変数を入れたい...
-
構造体のextern方法
-
define で 配列
-
c言語
-
C#で構造体の配列を持った構造...
-
C言語の2次元配列 容量が大き...
-
c言語 構造体
-
C言語 ファイルの指定された行...
-
C言語についてです 5人のテスト...
-
int i, int i[1];
-
fclose()でセグメンテーション違反
-
char型配列をint型に代入するには
-
C言語から質問です。
-
Cのエラー
-
コンボボックスでデフォルト値...
-
C言語の課題が出たのですが自力...
-
MFCのCArrayを使った二次元配列
-
[C++]const int と配列
おすすめ情報