• 締切済み

大きなファイルの読み書き

WindowsXP + SDKにてC++の開発をしています。 ディスクから50MB程度のファイルを読んで処理を施しまた書き戻すという事をやっていますが HANDLE handle; char fileName[256]; strcpy(fileName , "ファイル名"); handle = CreateFile(fileName , GENERIC_READ , NULL , NULL , OPEN_EXISTING , FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL ,NULL); としてファイルのオープンには成功するのですが OVERLAPPED ol; unsigned long size; unsigned long readSize; unsigned char *mem; ReadFile(handle , mem , readSize , &size , &ol) としていざ読もうとすると "ERROR_NO_SYSTEM_RESOURCES"が戻ってきて処理がとまってしまいます。 今までまったく同じコードで1~12MB程度のファイルは問題なく読み書き出来ていたのですが50Mのファイルを扱おうとしたところ問題が発生してしまいました。 FILE_FLAG_NO_BUFFERING と FILE_FLAG_OVERLAPPEDをはずすと読めるのですが余りにもアクセスが遅いので使い物になりません。 何か回避方法がありましたら御教授願います。

みんなの回答

回答No.3

 こんばんは。  100Mbyte位のファイルで試して見たのですが、確かに上手くいきません(手法が悪いのかもしれません)。  容量が大きくて、其れでいて可能な限り高速と言うのですから、恐らくDirect??系で映像や音像を流すのかな、と思います。  当方は使用した事が無いのですが、メモリマップドファイルが処方箋と成るかもしれません。  http://msdn.microsoft.com/ja-jp/library/cc430039.aspx

全文を見る
すると、全ての回答が全文表示されます。
  • chie65535
  • ベストアンサー率43% (8536/19406)
回答No.2

>としていざ読もうとすると >"ERROR_NO_SYSTEM_RESOURCES"が戻ってきて処理がとまってしまいます。 バッファリング無しでオーバーラップさせるには、指定する読み込みバッファに、必要なだけの実メモリが確保されていなければなりません。 この読み込みバッファは、スワップアウトされたり、メモリマネージャにガベージコレクトされたりして移動しない必要がありますので「ReadFileの呼び出し時に、指定しただけの物理的な空きメモリ」が必要です。 もし、空きメモリが無いのであれば、メモリ(つまりリソース)が足りないので、ERROR_NO_SYSTEM_RESOURCESでエラーになって当たり前です。 >OVERLAPPED ol; >unsigned long size; >unsigned long readSize; >unsigned char *mem; >ReadFile(handle , mem , readSize , &size , &ol) memとreadSizeが未初期化ですが、本当にこれで動いてますか? >FILE_FLAG_NO_BUFFERING と FILE_FLAG_OVERLAPPEDをはずすと読めるのですが余りにもアクセスが遅いので使い物になりません。 最低限必要なだけのメモリを確保して、そして、そのメモリをFixedステートメントでガベージコレクションされないようにして、読み書きを繰り返す。 「一気に全部読んで、処理して、一気に全部書いて」と言うのは非現実的。 もし「読み込んだサイズ」が「実メモリの実装サイズを遥かに超えるサイズ」の場合、仮想メモリと実メモリのスワップが多発し、膨大な量のディスクアクセスが発生します。 この時「プログラムでアクセスしているドライブ装置」と「仮想メモリをスワップしているドライブ装置」が同一の場合、同一ドライブ装置へのアクセスが集中し「まるでフリーズしたかのような速度」になります(シーク&リード、シーク&ライトが激しく頻発します) 「一気に全部読んで」が必要なのは、例えば「ファイルに書かれた内容により、どこをどう書き換えるかが決まり、常にランダムにアクセスする必要がある時」だけです。 普通は「先頭から、特定のブロック単位で、読んで書いてを繰り返す」で済む筈です。アルゴリズムを考え直す必要があるでしょう。 普通「ある一瞬、瞬間的に、ファイル内のすべてのデータが見えてないと処理出来ない」って事は有り得ない筈です。 場合によっては「処理上、前後256キロバイトのデータが見えてないと処理できない」って事はあるかも知れませんが、その場合は512キロバイトのバッファがあれば済みます。 もし「ある一瞬、瞬間的に、ファイル内のすべてのデータが見えてないと処理出来ない」のなら、処理ルーチンの設計ミスです。処理ルーチンを作り直しましょう。

全文を見る
すると、全ての回答が全文表示されます。
  • nda23
  • ベストアンサー率54% (777/1415)
回答No.1

先ず、一度に全データを読み込む必然性は何ですか? データの安全性を考えると、Aファイル→メモリ→Aファイルでは 危険です。メモリ→Aファイルの最中に障害が起きたらどうする のでしょう?安全性、再実行性を考えると、以下の流れでしょうか。 Aファイル→メモリ→Bファイル→BからAへCopy→Bを削除 別に1レコード(掲題の例では256か?)ずつ処理しても良いのでは? それともミリ秒を争うというような要求があるのでしょうか?

sakichichi
質問者

お礼

回答ありがとうございます。 画像の連番ファイルを読み出して画面に表示・再生させています。 今まで2048x1556を最大としていましたが4096x3112サイズのファイルを扱うことになった為に引っかかってしまいました。 このサイズのファイルをリアルタイムで再生することはかなり難しいのは承知していますが、少しでも高速に表示をしたいというのが理由です。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • エラーの原因は?「この関数の定義が見つかりません」

    <プログラム環境> Windows XP VC++6.0 MFC AppWizard(exe) ダイアログベース <症状> ヘッダー void Transmit(HANDLE,OVERLAPPED,unsigned char[],DWORD,CString); cppファイル void CMyDlg::Transmit(HANDLE hCom,OVERLAPPED old,unsigned char ucBuf[],DWORD dwByte,CString s) { } とコーディングしていて、ビルドも実行も全く問題ないのですが、 ClassViewでTransmit(HANDLE,OVERLAPPED,unsigned char[],DWORD,CString) をダブルクリックして、関数に移ろうとすると 『この関数の定義(インプリメンテーション)が見つかりません』 というエラーが出ます。 <質問> このエラーは何が原因で出ているのでしょうか?? 宜しければご指摘の程お願い致します。

  • ファイルの内容の表示

    実行時のコマンドライン引数で指定したファイルの内容を、行番号付きで画面に表示するプログラムを作る という問題です。ヒントも与えられています。 行番号付きの表示、コマンドライン引数の利用。両者を組み合わせればできるはずだ >  main関数の引数にargcとargvを指定して、コマンドライン引数をファイル名として利用する。キーボード入力を促す文(プロンプト)や改行チェックは不要なので書かないこと >  コマンドライン引数が指定されない場合は、メッセージを表示してプログラムを終了 >  ファイルの内容を画面表示する処理は、ユーザー定義関数put_file_contentsに記述する。仮引数には文字型のポインタ変数をひとつ指定し、ファイル名を受け渡せるようにする。put_file_contents自体の型は整数型(int)で、正常終了なら返り値0を返すこと。 行番号付きのプログラム#include<stdio.h> > int put_file(char *filename); > > int main() > { > char line[50]; > char *ptr; > > printf("ファイル名を入力:"); > fgets(line,sizeof(line),stdin); > ptr = line + strlen(line) - 1; > if(*ptr == '\n') { > *ptr = '\0'; > } > > put_file(line); > > return 0; > } > > int put_file(char *filename) > { > FILE *fp; > char buf[100]; > int line_no; > > fp = fopen(filename,"r"); > if (fp == NULL){ > printf("%sを開けません\n",filename); > return 1; > } > line_no = 1; > while (fgets(buf,sizeof(buf),fp) != NULL){ > printf("%3d: ",line_no); > printf("%s",buf); > line_no++; > } > fclose(fp); > > return 0; > } で、コマンドライン引数のプログラムは#include<stdio.h> void write_key_inputs(char *filiname); int main(int argc, char *argv[1]) { write_key_inputs(argv[1]); return 0; } void write_key_inputs(char *filename) { FILE *fp; char buf[100] ; fp = fopen(filename,"w"); while(fgets(buf, sizeof(buf),stdin) != NULL) { fputs(buf, fp); } fclose(fp); return ; } です。これらを組み合わせて少しいじると出来るみたいなのですが、できていません。ちなみに私が考えたプログラムは #include<stdio.h> int put_file_contents(char *filename); int main(int argc,char *argv[]) { int i; if(argc == 1){ printf("コマンドライン引数がありません\n"); return 1; } for(i = 0;i<argc;i++) printf("argv[%d]は「%s」です\n",i,argv[i]); put_file(i); return 0; } int put_file(char *filename) { FILE *fp; char buf[100]; int line_no; fp = fopen(filename,"r"); line_no = 1; while (fgets(buf,sizeof(buf),fp) != NULL){ printf("%3d: ",line_no); printf("%s",buf); line_no++; } fclose(fp); return 0; } です。コマンドライン引数は表示されるのですが、行番号が表示されません。どうしたらいいでしょうか??

  • CreateFileしてもうまくいきません・・。

    シリアルポートで通信するためのプログラミングを始めたばかりなのですが、COMポートのオープンが成功しません。 以下を実行しているのですが、何が間違いでしょうか? ちなみに、PCMCIAに挿入したPCカードから通信したいと考えています。単純に"COM1"というのであっているのかも分かりません・・。 よろしくお願いします。 void CMyDlg::OnReset() { HANDLE hCom; hCom = CreateFile( "COM1", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED NULL ); if(hCom == INVALID_HANDLE_VALUE){ MessageBox("ポートオープン失敗"); } else{ MessageBox("ポートオープン成功"); } }

  • C言語でファイル読み書きを早くしたい。

    いつも利用させてもらって助かっています。 あるプログラムを作成しているのですが、ファイル入力の部分がネックとなってしまって、全体が使いものにならない状況に陥っています。 たくさんのデータをfread1回で読み込むことにより、読み込み速度はずいぶんと改善されましたが、まだ圧倒的に遅い状況です。システムコールを使いましたが、ほとんど改善されませんでした。 読み込み/書き込みの速度を改善する方法として,SSDメモリを使ったりする方法があると思いますが,プログラムの観点から改善できるところはないでしょうか? 下に、ファイル読み込みの部分だけ記述したコードを添付させて頂いたので、改善できる点があれば、御指摘頂けると助かります。 なお、前提として, (1)データはスタック領域だと不足するので、ヒープ領域に確保 (2)データファイルは改行無しの一連のデータ とします。 ちなみに、環境は OS   : CentOS5.3 memory   : 6GB コンパイラ : gcc です。 よろしくお願いします。 //----------------------------------------------------- //通常バージョン #include <stdio.h> #include <stdlib.h> #define SIZE (512*1024*1024) //500MB int main(void) { unsigned long int i; unsigned char *data; FILE *fp; data = (unsigned char *)malloc(SIZE); if(data == NULL) { printf("メモリが確保できません\n"); exit(EXIT_FAILURE); } fp = fopen("filein.dat", "rb"); fread( data, sizeof( unsigned char), (int)SIZE, fp ); fclose(fp); /* //表示 for( i=0; i<SIZE; i++ ){ printf("%2x", data[i]); } puts(""); */ fp = fopen("fileout.dat", "w"); fwrite( data, sizeof( unsigned char), (int)SIZE, fp); fclose(fp); free(data); return 0; } //----------------------------------------------------- //readシステムコールを使ったバージョン #include <stdio.h> #include <stdlib.h> #define SIZE (512*1024*1024) //500MB int main(void) { unsigned long int i; unsigned char *data; data = (unsigned char *)malloc(SIZE); if(data == NULL) { printf("メモリが確保できません\n"); exit(EXIT_FAILURE); } int fd; fd = open( "filein.dat" ); read( fd, data, sizeof(unsigned char)*SIZE); close(fd); /* //表示 for( i=0; i<SIZE; i++ ){ printf("%2x", data[i]); } puts(""); */ FILE *fp; fp = fopen("fileout.dat", "w"); fwrite( data, sizeof( unsigned char), (int)SIZE, fp); fclose(fp); free(data); return 0; }

  • 文字の後の*の意味

    C言語初心者です。 あるプログラムの中で FILE* fopenread(const char* filename)・・・・(A) {FILE* file = fopen(filename, "r");・・・・・(B) if (file==NULL) {fprintf(stderr, "cannot open %s\n", filename); exit(-2);}・・・・(C) return file; } という関数があるのですが これはいったい何をしているのかがわかりません。 1. (A)は「FILE* fopenreadという名前の関数を定義し、 その引数が定数でchar型のfilenameという名前」ということでしょうか?たとえば適当な文字pを用いて「*p」のような表記ならば 「ポインタを使いますってことを言ってるんだな」ってことはわかるのですがここでは文字の後に*がついてます。これは何なのでしょうか?? 2.(B)はfilenameという名前のファイルを読み込みを目的として開く。FILE* file という変数に入れる。 3.(C)ファイルの中身がない場合は、cannot open と標準エラー出力に表示する。exit(-2);っていうのは何でしょうか??? 基本的なことばかりかもしれませんが自分なりに調べてもよくわからなかったので、 詳しい方、アドバイスしていただければと思います。 よろしくお願いします。

  • C言語 fopen

    初心者の質問になります。現在ファイルがオープンできるかどうかを確認したいのですが、指定したディレクトリの中のファイルを指定しているのですが、オープンできませんという結果が返ってきます。同じ場所にファイルを置いてファイル名だけでしていするとオープンが出来ます。 何卒よろしくおねがいします。 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main(void) { FILE *fp; char *filename = "/file/d20151001.csv"; fp = fopen(filename,"r"); if (fp == NULL) { printf("\aファイルをオープンできません\n"); } else { printf("ファイルがオープンできました\n"); fclose(fp); } return (0); } ディレクトリ(わかりにくくてすいません汗) file------d20151001.csv data.c 環境 VisualStudio

  • InternetReadFileを使ったファイルダウンロード

    下のようなプログラムは、httpサーバから特定のファイルを ダウンロードすることが目的です。 (※referer, file名は仮のものです。) 試しに動かしてみて、転送速度が比較的速い場合には、一応問題なく ダウンロードすることができたのですが、転送速度が遅い場合には、 ファイルサイズがどんどん膨れ上がってしまいます。 問題は、InternetReadFileでブロックされることがないからだと 推測しましたが、情報が少なく困っています。 転送速度が遅い場合にも正常にダウンロードするにはどうしたら よいでしょうか? #include <windows.h> #include <wininet.h> #include <stdio.h> #include <stdlib.h> bool GetHttpFile(){   HINTERNET hInternet;   HINTERNET hFile;   char Buf[1000]; /* バッファ */   DWORD ReadSize;   BOOL bResult;   wchar_t szHead[] = TEXT("Referer:http://aaa.com/\r\n\r\n"); // ヘッダにRefererを追加する   FILE *fp;   bool ret;   /* 保存先ファイル作成/open */     fp = fopen("sample.zip", "wb");   if (fp == NULL){  /* ファイル作成/openに失敗 */     ret = false;        }else{ /* ファイル作成/openに成功 */     /* WININET初期化 */     hInternet = InternetOpen(       TEXT("Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)"),       INTERNET_OPEN_TYPE_PRECONFIG,       NULL,       NULL,       0);        /* URLのオープン */     hFile = InternetOpenUrl(       hInternet,       TEXT("http://aaa.com/bbb.zip"),       szHead,       0,       INTERNET_FLAG_RELOAD,       0);        /* オープンしたURLからデータを(1000バイトずつ)読み込む */     for(;;){       ReadSize = 1000;          bResult = InternetReadFile(         hFile,         Buf,         1000,         &ReadSize);          /* 全て読み込んだらループを抜ける */       if(bResult && (ReadSize == 0)) break;              /* ファイルに書き込み */       fwrite(Buf, sizeof(char), 1000, fp);     }        /* 後処理 */     InternetCloseHandle(hFile);     InternetCloseHandle(hInternet);     fclose(fp);     ret = true;   }      return ret; } int main(){   if(GetHttpFile() == true){     printf("成功\n");   }else{     printf("失敗\n");   }      return 0; }

  • union共同体の使い方…

    typedef union {  A_FILE* aFile;  B_FILE* bFile; }C_FILE; 上記のようにunion共同体で2つの型を 対応するものを作りました。 ファイルをオープンするのに C_FILE file_Open( const char *filename); というI/Fを作りました。 でもファイルをクローズする時に ファイルハンドルを渡そうと思うのですが、 ファイルハンドルの引数をどっちの型が入っても よいようにしたいのですが。 int file_Close(C_FILE.aFile Fp) ←これでは意味がない… int file_Close(C_FILE Fp)  ←こういう使い方は出来ませんよね? ファイルオープン側に実体を持ったままで、 どっちの型が入ってもよいファイルクローズを行う I/Fを作るのは無理なのでしょうか。 やはり実体は呼びだす側にあるべきなのでしょうか?

  • C言語のファイル読み込みに関して。

    英文を入力したテキストファイルを読み込むプログラムをつくっているのですが、 ファイル読み込みが上手くできません。 #include<stdio.h> main() { char filename[33]; char sty[512]; FILE *fp; printf("FILENAME: "); fgets(filename, 33, stdin); //読み込むテキストファイルを指定 fp = fopen(filename,"r"); if(fp == NULL){ printf("Can't open the file!\n"); return -1; } fgets(sty, 512, fp); fclose(fp); printf("%s\n",sty); } このプログラムなのですが、どうしても"Can't open the file!"が表示されてしまいます。 どうすればいいのでしょうか?

  • 構造体のメンバにファイルポインタがあるときの初期化について

    #include<stdio.h> typedef struct file{ FILE *fp; char filename[255]; int flag; }sFILE; main() { sFILE fp={ ,"output.txt",1100}; } のように書きたいんですが、sFILE fp={ ,"output.txt",1100};の最初のファイルポインタのところは何を入れたらいいんでしょうか?