C言語関係掲示板

過去ログ

No733 ディレクトリの作成日付を名前に持つファイルをシステム日付と比較して、3ヵ月前なら削除したい

[戻る] [ホームページ]
No.8996

あるディレクトリの作成日付を名前に持つファイルをシステム日付と比較して、3ヵ月前なら削除したい
投稿者---バンビ(2003/08/20 21:36:41)


はじめまして。

掲示板に掲載するのは、初めてで、どのように書いていいのか分からず、
読み難いかもしれませんが、教えて下さい。
C言語が全く分からず、困っていますです。

やりたい事は、ほぼ件名の通りなのですが、
「あるディレクトリの作成日付を名前に持つファイルをシステム日付と比較して、8ヵ月前なら削除したい」
のです。

一番困っているのが、日付比較の所です。
日付の間隔って、difftime関数でとれるというのは調べたのですが、
戻り値は秒ですよね?8ヶ月を秒になおすと恐ろしい事になりそうで、
もっといい方法があるのではと思うのですが、分かりません。

次に困っているのが、ファイル名が以下の2種類で、
日付情報が始まっている位置がバラバラなのです。
C言語もワイルドカードで探す事ってできそうなのですが、
いまいち分かりません。

ファイル名
仝朕優魁璽(4桁) & "-" & YYMMDDHHMMSS
∪別(2桁) & "-" & 個人コード(4桁) & "-" & YYMMDDHHMMSS

どなたか教えて下さいませんか?
よろしくお願い致します。



No.8997

Re:あるディレクトリの作成日付を名前に持つファイルをシステム日付と比較して、3ヵ月前なら削除したい
投稿者---物見遊山(2003/08/20 22:13:18)


>一番困っているのが、日付比較の所です。
>日付の間隔って、difftime関数でとれるというのは調べたのですが、
>戻り値は秒ですよね?8ヶ月を秒になおすと恐ろしい事になりそうで、
>もっといい方法があるのではと思うのですが、分かりません。

difftime(3)使うのはやっぱりダメなのですか?

3ヶ月・・・というか90日なら
if ((90 * 24 * 60 * 60) <= difftime(time1, time2))
って感じで書けるような・・・。
8ヶ月、というか240日なら
if ((240 * 24 * 60 * 60) <= difftime(time1, time2))
って感じで書けるような・・・。

>次に困っているのが、ファイル名が以下の2種類で、
>日付情報が始まっている位置がバラバラなのです。
>C言語もワイルドカードで探す事ってできそうなのですが、
>いまいち分かりません。
>
>ファイル名
>仝朕優魁璽(4桁) & "-" & YYMMDDHHMMSS
>∪別(2桁) & "-" & 個人コード(4桁) & "-" & YYMMDDHHMMSS

strrchr(3)を使えばよろしいかと。

#include <stdio.h>
#include <string.h>

const char *
cut_ymdhms(const char *fn_pattern)
{
    const char *ret = NULL, *p = strrchr(fn_pattern, '-');
    if (p != NULL) ret = p + 1;

    return ret;
}

int
main(void)
{
    const char fn_pattern1[] = "0010-030820220000";
    const char fn_pattern2[] = "01-0020-030815123456";
    const char *p = NULL;

    p = cut_ymdhms(fn_pattern1);
    if (p != NULL) puts(p);
    p = cut_ymdhms(fn_pattern2);
    if (p != NULL) puts(p);

    return 0;
}


No.8998

Re:あるディレクトリの作成日付を名前に持つファイルをシステム日付と比較して、3ヵ月前なら削除したい
投稿者---物見遊山(2003/08/20 22:20:54)


cut_ymdhmsの修正です。
#やっぱり急いで書いたらダメですな。
const char *
cut_ymdhms(const char *fn_pattern)
{
    const char *ret = NULL;

    if (fn_pattern != NULL)
        ret = strrchr(fn_pattern, '-');
    if (ret != NULL) ret++;

    return ret;
}


No.9037

Re:あるディレクトリの作成日付を名前に持つファイルをシステム日付と比較して、3ヵ月前なら削除したい
投稿者---バンビ(2003/08/25 09:18:41)


少しの間、出かけてしまっていて、掲示板を見る時間がありませんでした。
お返事遅くなってすみません。
ご指導、ありがとうございます。

教えていただいた通り、やってみました。

ファイル名から、日付部分のみを取得する事は、教えて頂いた通りの
やり方で上手くいきました。

しかし、日付比較の所で、difftime関数を使用しようとしましたが、
ファイル名から取得した文字列の値をdifftime関数の引数にすると、
処理が思惑通りに行きません。
型変換をしなければならないのかと思いますが、文字列を日付型に
変換する方法が分かりません。

教えて頂けないでしょうか?
よろしくお願い致します。


No.9041

Re:あるディレクトリの作成日付を名前に持つファイルをシステム日付と比較して、3ヵ月前なら削除したい
投稿者---たか(2003/08/25 14:23:53)


これで差の秒数 = 7776000(3ヶ月の秒数) 以上ならば消せばどうでしょうか。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

int mdays[][12] = {{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
                   {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};

int isleap(int year)
{
  return (year % 4 == 0  &&  year % 100 != 0  ||  year % 400 == 0);
}

int dayofyear(int y, int m, int d)
{
  int i;
  int days;		/* 日数 */

  days = d;
  for (i = 1; i < m; i++)
    days += mdays[isleap(y)][i - 1];
  return (days);
}

const char *cut_ymdhms(const char *fn_pattern)
{
    const char *ret = NULL;

    if (fn_pattern != NULL)
        ret = strrchr(fn_pattern, '-');
    if (ret != NULL) ret++;

    return ret;
}

char *cut_char(const char *str, int begin, int len)
{
  static char loc[128];

  strcpy(loc, str + begin);
  loc[len] = '\0';
  return loc;
}


struct tm maketm(const char *chartime)
{
  struct tm tmx = {0};
  int y, m, d;
  
  tmx.tm_sec = atoi(cut_char(chartime, 10, 2));
  tmx.tm_min = atoi(cut_char(chartime, 8, 2));
  tmx.tm_hour = atoi(cut_char(chartime, 6, 2));
  tmx.tm_mday = atoi(cut_char(chartime, 4, 2)) - 1;
  tmx.tm_mon = atoi(cut_char(chartime, 2, 2));
  tmx.tm_year = atoi(cut_char(chartime, 0, 2)) + 100;
	y = tmx.tm_year; m = tmx.tm_mon; d = tmx.tm_mday;
 	if (m < 3) {
		y--; m += 12;
	}
  tmx.tm_wday = (y + (int)(y / 4) - (int)(y / 100) + (int)(y / 400) + (int)(2.6 * m + 1.6) + d) % 7;
  tmx.tm_yday = dayofyear(tmx.tm_year + 2000, tmx.tm_mon, tmx.tm_mday + 1);

  return tmx;
}

int main(void)
{
    const char fn_pattern1[] = "0010-030820220000";
    const char fn_pattern2[] = "01-0020-030823123456";
    const char *p = NULL;
    time_t t1, t2;
    struct tm tm1, tm2;
    double diff;
    
    p = cut_ymdhms(fn_pattern1);
    if (p != NULL) puts(p);
    tm1 = maketm(p);
    t1 = mktime(&tm1);
    
    p = cut_ymdhms(fn_pattern2);
    if (p != NULL) puts(p);
    tm2 = maketm(p);
    t2 = mktime(&tm2);
    diff = difftime(t2, t1);
    printf("差の秒数 = %f\n", diff);
    
    return 0;
}


No.9068

Re:あるディレクトリの作成日付を名前に持つファイルをシステム日付と比較して、3ヵ月前なら削除したい
投稿者---物見遊山(2003/08/26 18:37:06)


いやー、返事が遅くなってしまいました。

>ファイル名から取得した文字列の値をdifftime関数の引数にすると、
>処理が思惑通りに行きません。
>型変換をしなければならないのかと思いますが、文字列を日付型に
>変換する方法が分かりません。

たかさんが別途回答されているのでいいかなー、とも思ったのですが
せっかく作ったのでUPします。
バグがあるかもしれませんので心して見て下さい。
int
ymdhms2tm(const char *str, struct tm *inout)
{
    char buf[256] = {'1', };
    char *ymdhms = &(buf[1]);
    int i;
    int ret = 1;

    if (str == NULL || inout == NULL) goto end;

    for (i = 0; i < 256 - 2 && *str != '\0'; i++) {
        ymdhms[i] = *str;
        if (i % 3 == 2)
            ymdhms[i] = ' ';
        else
            str++;
    }

    if (sscanf(buf, "%d%d%d%d%d%d", &(inout->tm_year),
                                    &(inout->tm_mon),
                                    &(inout->tm_mday),
                                    &(inout->tm_hour),
                                    &(inout->tm_min),
                                    &(inout->tm_sec)) != 6)
        goto end;

    // 1970年から2037年の範囲なら多分OK
    if (inout->tm_year >= 170) inout->tm_year -= 100;

    ret = 0;
end:
    return ret;
}

第一引数にcut_ymdhmsの戻り値を、第二引数にstruct tm型構造体のアドレスを
指定すれば第二引数に適切な値を設定してくれます(多分)。
戻り値0が成功で1が失敗です。

No.9071

Re:あるディレクトリの作成日付を名前に持つファイルをシステム日付と比較して、3ヵ月前なら削除したい
投稿者---たか(2003/08/26 21:08:46)


tm.ydayを設定せずに正しくmktime()は動作しましたか?
私の環境(Boland C++ 5.6.4)ではtm.ydayを設定しないとどうしても
mktime()が-1を返すので仕方なく自前で年内の経過日数を計算して
代入しました。

No.9072

Re:あるディレクトリの作成日付を名前に持つファイルをシステム日付と比較して、3ヵ月前なら削除したい
投稿者---かずま(2003/08/26 22:07:55)


> バグがあるかもしれませんので心して見て下さい。
tm_mon の値は、0〜11 でないとだめです。また、mktime で、
tm_wday と tm_yday の値は無視されますが、tm_isdst の値は必要です。

int ymdhms2tm(const char *str, struct tm *p)
{
    if (sscanf(str, "%2d%2d%2d%2d%2d%2d",
            &p->tm_year, &p->tm_mon, &p->tm_mday,
            &p->tm_hour, &p->tm_min, &p->tm_sec) != 6) return 1;
    if (p->tm_year < 70) p->tm_year += 100;
    p->tm_mon--;
    p->tm_isdst = -1;
    return 0;
}


No.9076

Re:あるディレクトリの作成日付を名前に持つファイルをシステム日付と比較して、3ヵ月前なら削除したい
投稿者---物見遊山(2003/08/27 10:22:58)


みなさま、ご指摘ありがとうございます。
UPして良かったとつくづく思います。

たかさん>
tm構造体のメンバ変数であるtm_ydayとtm_wdayは
かずまさんのおっしゃるとおり、指定する必要がありません。
「えー、tm構造体ってこんなにメンバあるのかよ!
 どれか省けるものねーか?」と思って調べたのでした。

かずまさん>
tm_monの範囲については凹みました。ベッコンベッコンに。
かようなケアレスをしてしまうとは・・・。

それよりも、ものみにとってもっと重要だったのはtm_isdstのご指摘です。
実際のプログラムではUPした関数だけでなく
2つの日付が90日以上離れているか判定している部分まで作成していたのです。
で。ymdhms2tmの呼び元の関数で
    struct tm t = {0};
    ymdhms2tm(p_ymdhms, &t);

としてましたがUPしたのはymdhms2tmのみなのでした。
他人に使ってもらうライブラリ関数の作成ってホント難しいと思いました。

あと。sscanf(3)の小ネタ、いただきます。

No.9078

Re:あるディレクトリの作成日付を名前に持つファイルをシステム日付と比較して、3ヵ月前なら削除したい
投稿者---たか(2003/08/27 12:01:19)


tm_isdstについては初期化の際に{0}を代入して全部のメンバを0にしてい
ます。

tm_ydayですが、昨日やった時は代入しないと動作しなかったようなので
すが、今日コメントアウトしてみると動作しました。どうも他の部分が
間違っていたようです。

かずまさん、ありがとうございました。

No.9083

Re:あるディレクトリの作成日付を名前に持つファイルをシステム日付と比較して、3ヵ月前なら削除したい
投稿者---ひかる1977(2003/08/27 13:08:05)


>次に困っているのが、ファイル名が以下の2種類で、
>日付情報が始まっている位置がバラバラなのです。
>C言語もワイルドカードで探す事ってできそうなのですが、
>いまいち分かりません。
>
>ファイル名
>仝朕優魁璽(4桁) & "-" & YYMMDDHHMMSS
>∪別(2桁) & "-" & 個人コード(4桁) & "-" & YYMMDDHHMMSS
>

scnadir()でディレクトリ検索をかけて、
取得したファイルに対してのワイルドカードチェックを行う手もあるのではないでしょうか。

fnmatch()関数を使えば、
C言語でもワイルドカードが使えるみたいです。

例:[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]

みないな感じです。
UNIXでは使用できると思います。