No.16764![]() |
ファイルからの読み込みについて 投稿者---ss(2004/09/11 10:43:15) |
||
日ごろよりこの掲示板にはお世話になっております。 今回ご質問させていただきたいのは、ファイルに書かれたデータを後ろから読み込むことが出来るかということです。 あるファイルに数をバイナリで保存してます。 通常freadで読み込みを行うとファイルの始めの数から読み込むと思うのですが それを最後の数から順に最初の数へと読み込みを行いたいのです。 ファイル内の数を並び替える(最後の数から最初の数へと)というのも1つの手だと 思いますが、並び替える時間を省きたいのでご質問させて頂きました。 ご存知の方いらっしゃいましたらよろしくお願いいたします。 |
No.16765![]() |
Re:ファイルからの読み込みについて 投稿者---RAPT(2004/09/11 11:01:24) |
||
fseek()とか。 基本的に、ファイル操作はシーケンシャル(連続)アクセスで、先頭から 最後尾までの一方向にしか読み出すことができません。 対策としては、fseek()位置を移動し、読み出す。→位置を前方移動し、読み出す。 といった流れになるでしょう。その結果、果たして後からソートするより、 効率が良いかどうかは、充分に検討する必要があると思います。 ファイルが巨大でメモリに収まらないほどというのであれば、後方から 読み出す方が良いかもしれません。 そこそこの大きさで、メモリに収まる大きさであれば、一度全部をメモリに 読み込み、あとはメモリ操作を行なう手法も在ります。 この2案を融合して、後から一定サイズのブロックに分け、ブロックを 読み出しては、メモリ操作。終わったら一つ前のブロックを読み出す... といった解決法もいいでしょう。 |
No.16768![]() |
Re:ファイルからの読み込みについて 投稿者---かずま(2004/09/11 16:42:33) |
||
> ファイルに書かれたデータを後ろから読み込むことが出来るかということです。 ファイルをメモリにマップすれば、どこでも自由に読めます。 Unix なら mmap()、Windows なら CreateFileMapping() を 調べてみてください。 |
No.16774![]() |
Re:ファイルからの読み込みについて 投稿者---かずま(2004/09/13 15:39:22) |
||
Windows で CreateFileMapping を使った例です。 #include <windows.h> #include <stdio.h> #define DATA_FILE "hoge.dat" void *m_map(const char *name) { HANDLE h, v; void *q; h = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); if (h == INVALID_HANDLE_VALUE) return NULL; v = CreateFileMapping(h, NULL, PAGE_READONLY, 0, 0, NULL); CloseHandle(h); if (v == NULL) return NULL; q = MapViewOfFile(v, FILE_MAP_READ, 0, 0, 0); CloseHandle(v); return q; } int main(void) { static int a[10] = { 11, 22, 33, 44, 55, 66, 77, 88, 99, 10 }; int i, *p; FILE *fp = fopen(DATA_FILE, "wb"); if (fp == NULL) return 1; fwrite(a, sizeof(int), 10, fp); fclose(fp); p = m_map(DATA_FILE); if (p == NULL) return 1; for (i = 10; i > 0; ) printf(" %d", p[--i]); printf("\n"); UnmapViewOfFile(p); return 0; } |
No.16775![]() |
Re:ファイルからの読み込みについて 投稿者---シャノン(2004/09/13 16:21:55) |
||
些細な指摘をさせてもらえば、 ファイルマッピングオブジェクトを閉じるのは、全てのビューのマップを解除した後にすべきです。 つまり、 void *m_map(const char *name) { // 中略 v = CreateFileMapping(h, NULL, PAGE_READONLY, 0, 0, NULL); CloseHandle(h); if (v == NULL) return NULL; q = MapViewOfFile(v, FILE_MAP_READ, 0, 0, 0); // CloseHandle はここですべきではない CloseHandle(v); return q; } int main(void) { // 中略 UnmapViewOfFile(p); // するとしたら、このへんで。 // CloseHandle( ... ); return 0; } と。 実際にはこんなコードは書けませんので、もう一ひねり必要ですが。 |
No.16780![]() |
Re:ファイルからの読み込みについて 投稿者---かずま(2004/09/13 20:33:58) |
||
> ファイルマッピングオブジェクトを閉じるのは、全てのビューの > マップを解除した後にすべきです。 その根拠は何ですか? Jeferey Richter の Advanced Windows の「第7章 メモリマップトファイル」 (改訂第3版なら第8章)に次のように書かれています。 : hFile = CreateFile(...); : hFileMapping = CreateFileMapping(hFile, ...); : pFile = MapViewOfFile(hFileMapping, ...); : // メモリマップトファイルを使う : UnmapViewOfFile(pFile); : CloseHandle(hFileMapping); : CloseHandle(hFile); : : 上記のコードは、メモリマップトファイルの "望ましい" 使い方を示した : ものである。しかし、ここには、コードが MapVewOfFile を呼び出したとき : に、システムがファイルオブジェクトとファイルマッピングオブジェクトの : 参照カウントをインクリメントしていることは示されていない。上記のコー : ドは次のようにも書き直せるだけに、この副作用は重要な意味を持つ。 : : hFile = CreateFile(...); : hFileMapping = CreateFileMapping(hFile, ...); : CloseHandle(hFile); : pFile = MapViewOfFile(hFileMapping, ...); : CloseHandle(hFileMapping); : // メモリマップトファイルを使う : UnmapViewOfFile(pFile); |
No.16781![]() |
Re:ファイルからの読み込みについて 投稿者---かずま(2004/09/13 20:48:10) |
||
> Jeferey Richter の Advanced Windows の「第7章 メモリマップトファイル」 > : ものである。しかし、ここには、コードが MapVewOfFile を呼び出したとき 訂正 Jeferey Richter --> Jeffrey Richter MapVewOfFile --> MapViewOfFile |
No.16782![]() |
Re:ファイルからの読み込みについて 投稿者---シャノン(2004/09/13 23:03:06) |
||
>> ファイルマッピングオブジェクトを閉じるのは、全てのビューの >> マップを解除した後にすべきです。 > その根拠は何ですか? MSDN Library for VS.NET 2003 の CreateFileMapping の記述です。 > ファイルマッピングオブジェクトを完全に閉じるには、 > UnmapViewOfFile 関数を呼び出してビューをすべてアンマップし、 > さらに、CloseHandle 関数を呼び出してマッピングオブジェクトの > ハンドルを閉じなければなりません。 > 最初に UnmapViewOfFile を呼び出す必要があります。 > ファイルマッピングオブジェクトのマップトビューは、内部で開いて > いるハンドルとオブジェクトの関連付けを維持しています。そして、 > ファイルマッピングオブジェクトに関連付けられているすべての > ハンドルが閉じるまでは、そのファイルマッピングオブジェクトは > 閉じないからです。 MapViewOfFile でマップした全てのビューに対し UnmapViewOfFile を 呼び出してマップ解除してから、CreateFileMapping で作成した ファイルマッピングオブジェクトを CloseHandle で閉じろ、と読めます。 > Jeferey Richter の Advanced Windows の > 「第7章 メモリマップトファイル」 > (改訂第3版なら第8章)に次のように書かれています。 #Advanced Windows …いいなぁ、欲しいなぁ。 (コード略) > : 上記のコードは、メモリマップトファイルの "望ましい" 使い方を示した > : ものである。しかし、ここには、コードが MapVewOfFile を呼び出したとき > : に、システムがファイルオブジェクトとファイルマッピングオブジェクトの > : 参照カウントをインクリメントしていることは示されていない。上記のコー > : ドは次のようにも書き直せるだけに、この副作用は重要な意味を持つ。 (コード略) これは、上のコード例が望ましいんだからそっちにすべきだと言ってるんじゃないでしょうか? 上のコードと下のコードが等価であるとは言っていません。 一見等価に見えるけれど、目に見えないところで、参照カウントをインクリメントしている。これが副作用。 等価に見えるけれど等価じゃないから、下のように書いちゃまずいよ。 俺にはそう読めましたが。 #MSDN には、CreateFile で開いたファイルハンドルも最後まで閉じるな #とは書いてありませんね…どれが正しいんでしょうかね? |
No.16783![]() |
Re:ファイルからの読み込みについて 投稿者---シャノン(2004/09/13 23:10:09) |
||
ちょい補足。 >これは、上のコード例が望ましいんだからそっちにすべきだと言ってるんじゃないでしょうか? >上のコードと下のコードが等価であるとは言っていません。 「次のようにも書き直せる」=「等価」と読めないことも無いのですが >一見等価に見えるけれど、目に見えないところで、参照カウントをインクリメントしている。これが副作用。 >等価に見えるけれど等価じゃないから、下のように書いちゃまずいよ。 >俺にはそう読めましたが。 元の文章に、俺なりに言葉を補うならば 上記のコードは、メモリマップトファイルの "望ましい" 使い方を示した ものである。しかし、ここには、コードが MapVewOfFile を呼び出したとき に、システムがファイルオブジェクトとファイルマッピングオブジェクトの 参照カウントをインクリメントしていることは示されていない(が、インクリメントはしっかり成されている)。 上記のコードは(一見)次のようにも書き直せる(ように見える)だけに、この副作用は重要な意味を持つ。 となりましたケド、いかがでせう? |
No.16784![]() |
Re:ファイルからの読み込みについて 投稿者---YuO(2004/09/14 02:12:04) |
||
>> 最初に UnmapViewOfFile を呼び出す必要があります。 >MapViewOfFile でマップした全てのビューに対し UnmapViewOfFile を >呼び出してマップ解除してから、CreateFileMapping で作成した >ファイルマッピングオブジェクトを CloseHandle で閉じろ、と読めます。 ん? MSDNのCreateFileMapping (6 Parameters) function [Base]には, To fully close a file mapping object, an application must unmap all mapped views of the file mapping object by calling UnmapViewOfFile, and close the file mapping object handle by calling CloseHandle. The order in which these functions are called does not matter. と書いてあります。 The order (in which these functions are called) does not matter. ですから,(関数を呼び出す)順番は重要じゃない,ですよね。 確かにandは時系列的な順番を意味する接続詞としても使いますが, 今回は次の文が次の文だけに日本語版は誤訳ではないかと。 >#MSDN には、CreateFile で開いたファイルハンドルも最後まで閉じるな >#とは書いてありませんね…どれが正しいんでしょうかね? とりあえず,95系に限った話になりますが, では開いたハンドルを使ってI/Oコールをするな, 一般的にはマッピングオブジェクトを閉じるまでは使うな,と書いてあります。 Windows Me/98/95: File handles that have been used to create file mapping objects must not be used in subsequent calls to file I/O functions, such as ReadFile and WriteFile. In general, if a file handle has been used in a successful call to the CreateFileMapping function, do not use that handle unless you first close the corresponding file mapping object. 使うな,というのですからCloseHandleの呼び出しも避けるべきかと。 それから,ファイルハンドルを閉じてしまうと該当ファイルに書き込むことが出来ます。 結果として,ファイルとマッピングが乖離するか, 意図せずマッピングの状態が変化してしまいます。 それを避けるために,ファイルハンドルは開いたままの方がよいかと。 #FILE_SHARE_WRITEを付けていない場合。 |
No.16785![]() |
Re:ファイルからの読み込みについて 投稿者---かずま(2004/09/14 02:46:22) |
||
> MSDN Library for VS.NET 2003 の CreateFileMapping の記述です。 >> ファイルマッピングオブジェクトを完全に閉じるには、 >> UnmapViewOfFile 関数を呼び出してビューをすべてアンマップし、 >> さらに、CloseHandle 関数を呼び出してマッピングオブジェクトの >> ハンドルを閉じなければなりません。 >> 最初に UnmapViewOfFile を呼び出す必要があります。 確かに、 http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/jpmemory/html/_win32_createfilemapping.asp にそう書かれていますね。でも、 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/createfilemapping.asp には、 : To fully close a file mapping object, an application must unmap all : mapped views of the file mapping object by calling UnmapViewOfFile, : and close the file mapping object handle by calling CloseHandle. : The order in which these functions are called does not matter. とあります。最後の行で「これらの関数が呼び出される順序は問題ではない」 となっています。 > これは、上のコード例が望ましいんだからそっちにすべきだと言ってるんじゃ > ないでしょうか? "望ましい" がダブルクオートされていることに注意してください。さらに、 Advanced Windoes では、2つ目のコードの後に、 : システムがファイルオブジェクトとファイルマッピングオブジェクトの参照カ : ウンタをインクリメントしているので、コードの冒頭でこれらのオブジェクト : をクローズしておけば、リソースリークの可能性を下げることができる。 とあります。すなわち、2つ目のコードが本当は望ましいと言っているのです。 > 上のコードと下のコードが等価であるとは言っていません。 最終結果には同じですが、途中経過でメモリマップトファイルを使うときに 存在するカーネルオブジェクト(ファイルオブジェクトとファイルマッピング オブジェクト)の参照カウントが異なります。リソースを余計に食っている。 ---------------------------------------------------------------------- hFile = CreateFile(...); // ファイルオブジェクトの参照カウントは 1 hFileMapping = CreateFileMapping(hFile, ...); // ファイルオブジェクトの参照カウントは 2 // ファイルマッピングオブジェクトの参照カウントは 1 pFile = MapViewOfFile(hFileMapping, ...); // ファイルマッピングオブジェクトの参照カウントは 2 // メモリマップトファイルを使う // 2つのカーネルオブジェクトの参照カウントはそれぞれ 2。 UnmapViewOfFile(pFile); // ファイルマッピングオブジェクトの参照カウントは 1 CloseHandle(hFileMapping); // ファイルマッピングオブジェクトの参照カウントは 0 になるので、この // オブジェクトが参照しているファイルオブジェクトの参照カウントを // デクリメントして 1。ファイルマッピングオブジェクトは消滅。 CloseHandle(hFile); // ファイルオブジェクトの参照カウントは 0。このオブジェクトは消滅。 ---------------------------------------------------------------------- hFile = CreateFile(...); // ファイルオブジェクトの参照カウントは 1 hFileMapping = CreateFileMapping(hFile, ...); // ファイルオブジェクトの参照カウントは 2 // ファイルマッピングオブジェクトの参照カウントは 1 CloseHandle(hFile); // ファイルオブジェクトの参照カウントは 1 pFile = MapViewOfFile(hFileMapping, ...); // ファイルマッピングオブジェクトの参照カウントは 2 CloseHandle(hFileMapping); // ファイルマッピングオブジェクトの参照カウントは 1 // メモリマップトファイルを使う // 2つのカーネルオブジェクトの参照カウントはそれぞれ 1。 UnmapViewOfFile(pFile); // ファイルマッピングオブジェクトの参照カウントは 0 になるので、この // オブジェクトが参照しているファイルオブジェクトの参照カウントを // デクリメントして 0。 // ファイルマッピングオブジェクトもファイルオブジェクトも消滅。 |
No.16787![]() |
Re:ファイルからの読み込みについて 投稿者---シャノン(2004/09/14 10:50:26) |
||
内容が被るので、YuO さんにもこっちでまとめてレスとさせていただきます。 > 最後の行で「これらの関数が呼び出される順序は問題では > ない」となっています。 はぁ…日本語版 MSDN をアテにしたのが間違いでしたか。 #確かに誤訳に覚えが無いわけじゃないけど、有効な一次情報として #使えないんですかね。あくまで翻訳サイト程度の参考文献か。 > Advanced Windoes では、2つ目のコードの後に、 > : システムがファイルオブジェクトとファイルマッピングオブジェクトの参照カ > : ウンタをインクリメントしているので、コードの冒頭でこれらのオブジェクト > : をクローズしておけば、リソースリークの可能性を下げることができる。 > とあります。すなわち、2つ目のコードが本当は望ましいと言っているのです。 そいつを最初から言ってくださいよ。 誤りを認めます。間違いを書き込んで申し訳ありませんでした。 #しっかりしてくれよ>MSDN 翻訳チーム |