VisualC++でのバイナリファイルのサイズの取得方法

このQ&Aのポイント
  • VisualC++でバイナリファイルのサイズを取得する方法について説明します。
  • 通常の方法ではなく、空読みする方法でサイズを取得できることがわかりました。
  • Cの仕様の変更か、VC++の特殊な動作か、他の方法があるかどうかを検討しています。
回答を見る
  • ベストアンサー

VisualC++でのバイナリファイル

VisualC++でのバイナリファイルのサイズの取得。 Win7 x64 VC++2012 調べた所によると、 バイナリモードではNULL文字を使用できるため、 FILE* fp; fopen_s(&fp,"data.bin","rb"); fseek(fp,0,SEEK_END); size_t fsize=ftell(fp_cl); //fseek(fp,0L,SEEK_SET);//元の位置に戻す。 fclose( fp ); のような感じでサイズを取得してはいけない。 (fseekのSEEK_END動作が不定のため) ……と思っていたのですが、他に方法と言えば、 ファイルを一度全て空読みするくらいしかないので、 試にやってみたところ、上手く行ってしまいます。 一応NULLの入ったバイナリでも正しく取得できてしまいました。 これはCの仕様が変わったためなのか、VC++がたまたま対応しているのか、 どちらでしょうか? また、他に上手い方法があればよろしくお願いいたします。

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

  • ベストアンサー
  • wormhole
  • ベストアンサー率28% (1619/5654)
回答No.3

肝心な事書き忘れてました _stat() を調べて見てください。 あとおそらくですがNUL文字と0x1aを勘違いされているかと思います。 CP/Mでは0x1aがファイル終端のコードとして扱われていたためMSDOSやその後継であるWindowsのCコンパイラでは互換性のためにテキストモードで0x1aを読み込んだ際にはファイル終端とみなすようになっています(Cのライブラリでそういう処理になってるというだけで本当にファイル終端というわけではありません)。

Erdbeerkegels
質問者

お礼

ありがとうございました。

その他の回答 (2)

  • wormhole
  • ベストアンサー率28% (1619/5654)
回答No.2

>(fseekのSEEK_END動作が不定のため) 「fseekのSEEK_ENDの動作が不定」というのはどういう事でしょうか? SEEK_ENDはファイル末尾基準という意味ですから、第2引数に0を指定すればファイル終端そのものですけど。 ファイル中にNUL文字があろうがなかろうが関係ありません。 これはテキストモードでも同様です。 勘違いされているようですがテキストモードでもNUL文字の読み書きはできます。 printf系やfgetsなどのNUL文字を文字列の終端として扱ってる関数ではNUL文字の読み書きがしにくいというだけです(文字列の終端のNUL文字なのかそうでないのかの区別がつかないから)。 >これはCの仕様が変わったためなのか、VC++がたまたま対応しているのか、どちらでしょうか? Cの仕様は変わっていませんしVC++もふつうに対応してるだけの事かと思いますが。

  • bardfish
  • ベストアンサー率28% (5029/17765)
回答No.1

バイナリモードでオープンしているから。 通常モードでオープンしていればNULLをファイルの終端と判断してしまう。 「rb」って「Read Binary」だと思いましたけど?

関連するQ&A

  • バイナリファイルの読み込み(C言語)

    raw(音楽ファイル)データを配列rawに読み込みたいのですが,バイナリファイルの読み込み方がわかりません. サンプルで以下のようなソース(途中略)があるのですが, ・なぜrawの型としてshortを使っているのか ・データ数の半分(file_size = ftell(fp) / 2)しか読み込んでいない ・fgetc(fp) << 8 あたりの意味がわからないので教えて下さい. -------------------------------------------------------- short *raw; if((fp=fopen(argv[1], "rb")) == NULL){ fprintf(stderr, "can't open %s.\n", argv[1]); exit(1); } fseek(fp, 0, SEEK_END); file_size = ftell(fp) / 2; fseek(fp, 0, SEEK_SET); raw = (short *)malloc((size_t)(file_size * sizeof(short))); if(raw == NULL){ fprintf(stderr, "malloc error\n"); exit(1); } for(i=0;i<file_size;i++) raw[i] = (short)((fgetc(fp) << 8) | fgetc(fp)); -----------------------------------------------------

  • ファイルサイズの取得について

    2つのテキストファイルのサイズを取得し、そのファイルサイズ分だけを動的にメモリを確保しようとしています。 int *c,*a;と宣言し、 fp=fopen("./data/Problem.txt","r");//1つ目のファイル fseek(fp, 0, SEEK_END); /* ファイルの終端までシーク */ size = ftell(fp); /* 終端の位置、すなわちファイルサイズを得る */ fseek(fp, 0, SEEK_SET); /* ファイルの先頭に戻る */ c = (int *)malloc(size); /* ファイルサイズ分メモリ確保 */ while((x=fgetc(fp))!=EOF){ c[i]=x; i++; } c[i]='\0'; i=0; fclose(fp); fpa=fopen("./data/Answer.txt","r");//2つ目のファイル fseek(fpa, 0, SEEK_END); size = ftell(fpa); fseek(fpa, 0, SEEK_SET); a = (int *)malloc(size); while((x=fgetc(fpa))!=EOF){ a[n]=x; n++; } a[n]='\0';//・・・・(1) n=0; fclose(fpa); とすると1つ目のファイルの方だけはうまくいくのですが、(1)の部分で 「sample.exeの0x00411dcでハンドルされていない例外が発生しました:0xc0000005:場所0x0000000に書き込み中にアクセス違反が発生しました。。」 というエラーが出ます。 また、 int *c,*a;を int *c,a[300]; のように片方を配列として宣言し、 //a = (int *)malloc(size); /* ファイルサイズ分メモリ確保 */ のようにコメントアウトすると上記のエラーは出ずにcにメモリは確保されているようです。 これは何故なのでしょうか? また、どうすればaとcでメモリを確保出来るようになるのでしょうか? よろしくお願いいたします。

  • Ç言語でファイルサイズを変更するプログラム

    Ç言語初心者です。visualstudio2010を使用しています。 ファイルサイズ100MBのtest.binをバイナリモードで開き、10GBになるまで0を追加するプログラムを組みたいと思います。 ファイルを読み込んで出力するようには組めたのですが、この手法だとファイルサイズが大きいと時間がかかってしまいます。 現在のソースは以下の様になっているのですが、どうしたらもっと早く終わらせることが出来るでしょうか? また、int型でファイルサイズを取得していますが、ファイルサイズがもっと大きくなったときにint型では足りなくなってしまうのもどうすればいいのか困っています。 ※元ファイルサイズ(test.bin)は例としています。今後?GBサイズになると思います。変更後のファイルサイズは今後10GBくらいまでで考えています。 #include <stdio.h> #include <string.h> #include "stdafx.h" #define KIRO (1024) #define MEGA (KIRO*1024) #define GIGA (MEGA*1024) #define SIZE (100) int main(void) { FILE *fp,*fpw; unsigned char c; unsigned char zero = 0; int i = 0; int filesize; // 元ファイルをバイナリモードで開く fp = fopen( "test.bin", "rb" ); if( fp == NULL ) { printf( "test.binが開けません" ); return 1; } fseek( fp, 0, SEEK_END ); filesize = ftell( fp ); fseek( fp, 0, SEEK_SET ); // 書込み先をバイナリモードで開く fpw = fopen( "test_W.bin", "wb" ); if( fp == NULL ) { printf( "test_W.binが開けません" ); return 1; } while(1) { i++; // 指定サイズになったら終了 if(i > MEGA * SIZE) break; // ファイルサイズまで読み書き if(filesize < i){ // 残りを0で代入 fwrite(&zero, sizeof(unsigned char), 1, fpw); /* 1文字ずつ書き込み */ }else{ // ファイルの内容を1文字ずつ読み書き fread( &c, sizeof(unsigned char), 1, fp ); /* 1文字ずつ読み込み */ fwrite(&c, sizeof(unsigned char), 1, fpw); /* 1文字ずつ書き込み */ } printf( "%d番目\n", i ); } printf( "\n" ); fclose(fp); fclose(fpw); return 0; }

  • Officeファイルの送受信

    CSocketを使って、Serverとのネットワークプログラムを 作成していますが、ファイルの送受信が上手く出来ず、困っています。 Server側で指定ファイルデータを読み込み、 Client側でファイルを作成し、オープンすると 中身が壊れていますとメッセージが出てしまいます。 下記は、ファイル送受信のためだけに、 暫定的に組んだソースの抜粋になります。 /* Server側のCAsyncSocket派生クラスのSend関数 -------------- */ int CServerSocket::Send( int nFlags ) { FILE *fp; char *pBuffer; fp = fopen( "C:\\a.doc", "rb" ); /* ファイルサイズを取得する */ long current = ftell( fp ); fseek( fp, 0, SEEK_END ); long size = ftell( fp ); fseek( fp, current, SEEK_SET ); /* ファイルデータ読み込み */ pBuffer = new char[size]; fread( pBuffer, sizeof(char), size, fp ); fclose( fp ); return CAsyncSocket::Send( pBuffer, size, nFlags ); } /* Client側のCSocket派生クラスのOnReceive関数 -------------- */ void CClientSocket::OnReceive( int nErrorCode ) { char aaa[22529]; while ( true ){ n_read = Receive( aaa, 22528 ); received += n_read; if ( received >= 22528 ) break; } Close(); ShutDown(); FILE *fp; fp = fopen( "C:\\test.doc", "wb" ); fwrite( aaa, sizeof(char), 22528, fp ); fclose( fp ); } ※テスト版ということで、Client側では、とりあえず、送信サイズ(ファイルデータサイズ)は  分かっているので、固定にしています。 このような送受信では、Officeファイルの送受信はうまく行かないものなのでしょうか?(ちなみにtxtファイルは上手く行きました)

  • ファイル名をチェックする方法。

    現在、PCからRS-232Cケーブル経由で端末機器のファームウェア更新の機能でバイナリファイルを選択してファームウェアをダウンロードする機能があるのですが、謝ってファイル選択時に同じフォルダ内にbinファイルが複数あった場合に別のバイナリを選んでしまうとそのままダウンロードしてしまい、端末機器が復旧できなくなってしまう問題があり困っています。 if(dlgOpen->Execute() == mrOk) { FILE *fp; int length; u8 *firmware; fp = fopen(AnsiString(dlgOpen->FileName).c_str(),"rb"); if(fp != NULL){ fseek(fp,0L,SEEK_END); length = ftell(fp); firmware = (BYTE *)malloc(length + 1 + sizeof(gate_t)); fseek(fp,0L,SEEK_SET); fread(&firmware[sizeof(gate_t)],1,length,fp); fclose(fp); firmware[sizeof(gate_t)+ length] = crc8(&firmware[sizeof(gate_t)],length); memcpy(firmware,(u8 *)m_pSelectItem,sizeof(gate_t)); SendFormMsg(m_hMain,TEST_FW_DOWNLOAD,(u8 *)firmware,sizeof(gate_t) + length+1); free(firmware); } たとえば、ファイルが”TEST.bin”というファイル名でない場合も”if(fp != NULL)”内の条件の処理は不一致のfalseとして処理したい場合はどうしたらよいでしょうか? どうぞ、ご協力の程よろしくお願い致します。

  • C言語のローカル変数の使い方について質問です。

    C言語の変数に関しての質問です。 グローバル変数を使わずに、関数内で宣言したローカルの変数を別のソースファイルで使用することって可能ですか? 例えば、a.cというソースファイルと、b.cというソースファイルがあります。 a.cの関数内で"FILE *fp;"と宣言したローカル変数を、b.cの関数内で共有して使うことはできるのでしょうか。 また、"fp"に直接アクセスはできなくても、間接的にアクセスできる方法があれば教えてください。 下に記述しているのは例え用に適当に書いたプログラムです。 --------------------- a.cのソースファイル --------------------- void Temp(void) { char file_name[128] = {}; errno_t error; FILE *fp; // ←この変数を別のソースで使いたいです scnaf_s("%s", file_name, 128); if(error = fopen_s(&fp, fname, "rb") != 0) { printf("ファイルがオープンできません"); return 0; } fclose(fp); } --------------------- b.cのソースファイル --------------------- void Temp2(void) { int size; // ここでa.cのTemp関数で宣言されている"fp"を使いたい fseek( fp, 0, SEEK_END ); fsize = ftell( fp ); fseek( fp, 0, SEEK_SET ); }

  • C言語 バイナリファイルをfloatにしたいのですが…

    16進数で表示すると以下のようなバイナリファイルがあります。 42 b9 e0 a4 3b df ea c0 3a 70 eb dc 37 7c f4 8c これを4バイトずつfloatに入れて出したいのですが、 本当はこのように出したいのですが、 [0][92.93875] [1][0.0068334043] [2][9.190419E-4] [3][1.50773085E-5] このような値がでてしまいます [0][-9.745835E-17] [1][-7.339750E+00] [2][-5.301601E+17] [3][-3.766891E-31] ソースはこれです。 #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { FILE *fp; long size, n; float *buf; int i = 0; if (argc != 2) return 1; /* FILE OPEN */ fp = fopen(argv[1], "rb"); if (fp == NULL) return 1; /* FILE SIZE */ fseek(fp, 0, SEEK_END); size = ftell(fp); rewind(fp); printf("FILE SIZE %ld\n", size); /* FILE READ */ buf = malloc(size); if (buf == NULL) return 1; n = fread(buf, 1, size, fp); /* FILE PRINT */ for(i=0;i<10;i++) { printf("[%d][%E]\n", i, buf[i]); } return 0; } 本日一日調べましたが良くわかりませんでした。 開発環境は以下の内容です。 $ uname -a Linux fedoracore6 2.6.20-1.2962.fc6 #1 SMP Tue Jun 19 19:27:14 EDT 2007 i686 athlon i386 GNU/Linux $ gcc --version gcc (GCC) 4.1.2 20070626 (Red Hat 4.1.2-13) Copyright (C) 2006 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 何かお知恵を拝借出来ないものでしょうか?? よろしくお願い致しますm(_ _)m

  • バイナリデータのファイル

    FILE *stream1; if( (stream1 = fopen( argv[2], "rb" )) == NULL ) printf( "Can not open plane text file.\n"); /////////////////////////////////////////////////////////////////// // 平文 fseek(stream1, 0, SEEK_END); long filelen = ftell(stream1); fseek(stream1,0,0); int head = sizeof(long); mesLength = filelen + head; int baseByte = kk / 8 + ((kk % 8)?1:0); // 鍵バイト長 int mesByte = baseByte - 1; // 処理単位バイト数(暗号化ではbyte減らしておく) //暗号化 if(mesLength <= mesByte*20){//63が暗号化の作業サイズ *20= bufp = (char*)new(char[filelen +1+ int(kk/8 + 2)+head]); if(bufp == NULL){ cout << "No Memory" <<"\n"; cout.flush(); return(-1); } // 平文 *(long *)bufp = filelen; int i = head; do{ c = fgetc(stream1); bufp[i]=c; i=i+1; }while(c!=EOF); bufp[i-1]=NULL; for(int j=0; j<(kk/8+2); j++){ bufp[j+i] = NULL; } mesLength = i-1; // 平文長(バイト) + head 上のように、古い形でファイルを扱っています。 wchar_t を基本にプログラムを書き換えようとしていますが、 ファイルの扱いで、上記の部分と似たような扱いがしやすいのは、 _wfopen CreateFile の、どちらでしょうか? バイナリファイルが扱いやすいもの、8ビットごとの操作が可能なものを探しています。 それとも、あきらめて古いままのほうが良いのでしょうか? よろしくご指導下さい。

  • ファイル処理について

    大学の課題なのですが、何度取り組んでもエラーになるため、間違いのご指摘、または正答を教えていただけないでしょうか。 問題は以下のものです。 【問題】 ファイルから整数を読み込み,その値によってfpの読み込み位置をかえ,何度目の読み込みで0を読み込んだかを表示するプログラムを作成せよ. ファイルの内容の例 2,4,0, fpの読み込み位置を変えるにはfseekという関数を利用する. fseekの使い方: 現在の読み取り位置xだけずらすには, fseek(ファイルポインタ, x, SEEK_CUR); と記述する. STEP 1 データを一区切りで読み取る("2,"や"-4,"などの整数とコンマの組) 2 読み取ったデータに応じてfpを移動させる("2,"なら2移動,"-4,"なら-4移動) 3 0を読むまで繰り返す +++++*+++++fseek-exercise.c+++++*+++++ #include <stdio.h> int main(void){ FILE *fp; int c; int i; int count=0; char filename[60]; printf("ファイル名 :"); scanf("%s",filename); //ファイルを開く // (* ここに解答を書き加える *) while(1){ printf("読み込み前 : %ld\n",ftell(fp)); //fpから値を読む // (* ここに解答を書き加える *) printf("読み込んだ値は%dです\n",c); printf("読み込み後 : %ld\n\n",ftell(fp)); //読み込み位置をずらす // (* ここに解答を書き加える *) } printf("%d回目です.",count); fclose(fp); return(0); } // 以上になります。 自分で作ったプログラムは以下のようになりました。 #include <stdio.h> int main(void){ FILE *fp; int c; int i; int count=0; char filename[60]; printf("ファイル名 :"); scanf("%s",filename); //ファイルを開く // fp = fopen(filename,"r"); if(fp == NULL){ printf("cannot open\n"); exit(1); } while(1){ printf("読み込み前 : %ld\n",ftell(fp)); //fpから値を読む // c = fgetc(fp); printf("読み込んだ値は%dです\n",c); printf("読み込み後 : %ld\n\n",ftell(fp)); //読み込み位置をずらす // if(c > '0' || c< '9'){ i = atoi(&c); count++; if(i == 0){ break; } fseek(fp,i,SEEK_CUR); } } printf("%d回目です.",count); fclose(fp); return(0); } // どこを訂正していいのかわかりません。 どうぞ、よろしくお願いいたします。

  • バイナリファイルをテキストファイルに変換する方法を教えて頂けませんか。

    こんにちは。 バイナリファイルをテキストファイルのように読み込んだり、書き込んだりすることは可能でしょうか。バイナリファイルをテキストファイルとして扱う良い方法があれば是非ご教授頂きたいです。 以下は自分なりに考えたプログラムなのですが、すごく文字化けして出力されてしまいます。どこがいけないんでしょうか。 ####プログラム#### #include<stdio.h> int main(){ FILE *fp,*fp2; char str[1024]; //file.txtはバイナリファイルなのでバイナリモードで開く if((fp = fopen("file.txt","rb")) == NULL){ printf("file.txt:open error"); exit(-1); } //out.txtはテキストファイルとして保存したいのでテキストモードで開く if((fp2 = fopen("out.txt","at")) == NULL){ printf("out.txt:open error"); exit(-1); } //一行ずつバイナリファイルをテキストファイルにして保存 while((fgets(str,1024,fp)) != NULL){ printf("%s\n",str); fprintf(fp2,"%s\n",str); } fclose(fp); fclose(fp2); return 0; } ####ここまで#### 以下が出力されたテキストファイル(out.txt)です。 ^A^Dc ^A^D^L<87> ^Y<98>X^?m?;^D&ordm;?^QI&egrave;&Ccedil; ^A^Dc ^A^D^L<87> ^Y<98>X^?m?;^D&ordm;?^QI0g 酷い文字化けを起こしてしまっています。 解決方法をご存知であれば教えて頂けないでしょうか。どうぞよろしくお願いします。

専門家に質問してみよう