C言語関係掲示板

過去ログ

No.143.テキストファイルだけ処理したい


No.910

ファイル読み込みで
投稿者---匡(2002/01/22 09:53:58)


テキストモードでファイル読み込みを行うようにモードを指定したのですが
バイナリも読み込めてしまいます。
バイナリのときは処理を終了したいのですが、どのように判断すればいいのでしょか?


No.912

Re:ファイル読み込みで
投稿者---B.Smith(2002/01/22 17:36:31)


こんにちは。

テキスト・バイナリの区別ですが、これはデータすべてをチェックしてみないと分かりません。一番簡単なのは、ファイル名の拡張子を取り出して種類を調べてみることですが、確実ではありません。
また、EXEファイルやBMPファイル等、データのどこかに印があるファイルは別ですが、それらのファイルが選ばれて指定されるわけではないと思いますので、ここでは、「表示(印字)可能な文字と、空白文字(改行やタブ文字を含む)しか存在しないファイルをテキストデータと見なす」とします。
サンプル1.
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

char    *LoadFile(char *);
int     CheckTextFile(char *);

void main(int argc,char *argv[])
{
    char    *ptr;

    ptr = LoadFile(argv[1]);
    if (!ptr){
        printf("fail.\n");
        return;
    }

    if (CheckTextFile(ptr))
        printf("Text file.\n");
    else
        printf("Binary file.\n");

    free(ptr);
}

/* 元データをメモリにロード */
/* 戻り値のポインタがNULL以外(正常終了)の場合、使用後に   */
/* 関数freeにより解放すること                               */
char    *LoadFile(char *FileName)
{
    FILE    *fp;
    size_t  wSize;
    char    *ptr;

    fp = fopen(FileName,"r");   /* リードオープン */
    if (!fp)    return NULL;

    wSize = (size_t )filelength(fileno(fp));   /* ファイルサイズ */

    /* メモリの確保 */
    /* テキストデータとして扱うため、末尾ヌル分を余計に確保 */
    ptr = (char *)malloc(wSize + 1);
    if (!ptr){
        fclose(fp);
        return NULL;
    }
    fread(ptr,wSize,1,fp);  /* 読み込み */
    fclose(fp);
    *(ptr + wSize) = 0;
    return ptr;
}

/* テキスト・バイナリファイルの区別 */
int     CheckTextFile(char *Buf)
{
    while(*Buf){
        /* 表示(印字)可能でなく、空白文字でもない場合ゼロを返す */
        if (!isprint(*Buf) && !isspace(*Buf))
            return 0;
        Buf++;
    }

    return 1;
}

サンプル1では、メモリ上にすべてのデータをロードし、1バイトずつ表示可能か、空白文字であるかをチェックして行きます。文字の区別は関数isprint、関数isspaceを使用します。しかし、この方法では、マルチバイト文字(全角文字)が含まれるデータがテキストデータとして認識できません。マルチバイト文字を含むファイルをテキストデータと見なすためには、コードの種類によりチェックする方法を変更しなければなりません。

(Windows環境の場合)
Windowsにはマルチバイト文字を考慮した関数が用意されています。この関数を利用すれば、上記の処理を比較的簡単に実装することができます。Windows版で良ければ、実用的にはこちらの方法をお勧めします。
サンプル2.
#include <windows.h>
#include <mbstring.h>

/* テキスト・バイナリファイルの区別 */
int     CheckTextFile(unsigned char *Buf)
{
    unsigned int        code;

    while(*Buf){
        /* マルチバイト文字の場合、現在の位置と一つ後ろの   */
        /* 2バイトを検査する                                */
        if (IsDBCSLeadByteEx(CP_ACP,*Buf) == TRUE)
            code = *Buf << 8 | *(Buf + 1);
        else
            code = (unsigned int )*Buf;

        /* 表示(印字)可能でなく、空白文字でもない場合ゼロを返す */
        if (!_ismbcprint(code) && !_ismbcspace(code))
            return 0;

        /* コードの種類により1バイトまたは2バイト進める */
        Buf = _mbsinc(Buf);
    }

    return 1;
}

Windowsに限らず、お使いの環境によっては似たような処理を行う関数が存在する可能性があります。まずは、ライブラリリファレンスを調べてみてください。


戻る


「初心者のためのポイント学習C言語」 Last modified:2002.03.06
Copyright(c) 2000-2002 TOMOJI All Rights Reserved