C++/C löschen von älteren Dateien

  • #1
N

nashia

Neues Mitglied
Themenersteller
Dabei seit
13.03.2006
Beiträge
2
Reaktionspunkte
0
Ort
Witzenhausen
hallo alle zusammen, also nach diesem Beitrag :
weiß ich nun, dass es mir anscheinend nicht möglich ist ein Datum (Wochentag) in einer batch Datei abzufragen.
Nun ist meine Frage wie sowas in C/C++ zu lösen wäre?
Könnte mir da jemand helfen?

Kurze Einleitung: ::)
Es gibt die Ordner Montag- Sonntag wenn das Montag Backup in den Monatgsordner geschoben wird, soll er den Dienstag schon einaml im Vorraus löschen.

Vielen Dank!
 
  • #2
Ein paar Funktionen:

Code:
DWORD getFileTime (const char* fname, time_t& ft) {
  WIN32_FILE_ATTRIBUTE_DATA wfad = {0}; 
  if (!GetFileAttributesEx(fname, GetFileExInfoStandard, (void*)&wfad))
    return GetLastError();
  else
  {     
    ft = FileTimeToTime(&wfad.ftLastWriteTime); // ftCreationTime, ...
    return ERROR_SUCCESS;
  }
}

time_t getCurTime() {
  return time(0);
}

DWORD getFileLocalDayOfWeek (const char* fname, int& dow) {  
  WIN32_FILE_ATTRIBUTE_DATA wfad = {0}; 
  if (!GetFileAttributesEx(fname, GetFileExInfoStandard, (void*)&wfad))
    return GetLastError();
  else
  { 
    SYSTEMTIME stUTC, stLocal;
    FileTimeToSystemTime(&wfad.ftCreationTime, &stUTC);
    SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
    dow = stLocal.wDayOfWeek;
  } 
  return ERROR_SUCCESS;
}

int getLocalDayOfWeek() {
  time_t now = getCurTime(); 
  return localtime(&now)->tm_wday;
}

time_t FileTimeToTime(FILETIME* ft) {
// Bed.: Zeit >= 1.1.1970, 00:00
  return (time_t) ((*(LONGLONG*)ft - 0x19DB1DED53E8000) / 10000000); 
}

DWORD fileDays(const char* fname, int& days) {
  const int secPerDay = 86400;
  time_t filetime;
  DWORD res = getFileTime(fname, filetime);
  if(res != ERROR_SUCCESS)
    return res;
  else {
    days = (int)(getCurTime() - filetime) / secPerDay;
    return ERROR_SUCCESS;
  }
}

BTW: Die kurze Einleitung ist ein bischen zu kurz, um Schlüsse daraus zu ziehen. Soll Dein Programm nur die Dateien im Verzeichnis des nächsten Tages löschen? Oder das Backup machen? Ist ja alles ein bischen anders als in dem Beitrag, auf den Du verwiesen hast. Wenn Du Hilfe brauchst, beschreibe bitte mal genau, was das Programm machen soll, was im Fehlerfall passieren soll, welche Windows-Version etc.
 
  • #3
Dings schrieb:
BTW: Die kurze Einleitung ist ein bischen zu kurz, um Schlüsse daraus zu ziehen. Soll Dein Programm nur die Dateien im Verzeichnis des nächsten Tages löschen? Oder das Backup machen? Ist ja alles ein bischen anders als in dem Beitrag, auf den Du verwiesen hast. Wenn Du Hilfe brauchst, beschreibe bitte mal genau, was das Programm machen soll, was im Fehlerfall passieren soll, welche Windows-Version etc.

hey danke schon mal !

Also folgendes: es ist ein Windows 2003 Server, auf dem irgendwo Ordner liegen 1-Monat, 2-Dienstag, 3-Mittwoch...uws bis Sonntag.
Der Exchange Server schiebt dann am Monat um eine bestimmte Uhrzeit das Backup (welches er von allein macht ^^) in den 1-Montag Ordner...

nehmen wir an der Task passiert um 23:00 uhr dann soll eine anderer Task aufgerufen werden, von mir aus um 15:00 am Montag ist ja schnubbe, der dann das Programm aufruft, das den Inhalt des Dienstagsordners löschen soll, damit Platz für das Dienstag Backup herrscht.
So kann man das glaube ich ganz Sinnvoll beschreiben.
 
  • #4
So in der Art könnte es funktionieren:

Code:
#include stdafx.h
#include <iostream>
#include <string>
#include <sstream>

const int ERROR_NONE            = 0;
const int ERROR_INI_OPEN        = 1;
const int ERROR_INI_SYN         = 2;
const int ERROR_OPEN_TARGET_DIR = 3;
const int ERROR_DEL_FILE        = 4;

std::string errStrings[] = {
  ,
  INI-Datei kann nicht geoeffnet werden.,
  Fehler beim Auslesen der INI-Datei im Abschnitt:,
  Auf das Zielverzeichnis kann nicht zugegriffen werden.,
  Loeschen der Datei fehlgeschlagen.
};

class Ini {
private:  
  static const std::string istr_basedir;
  static const std::string vstr_basedir;
  static const std::string istr_subdirs;
  static const std::string vstr_subdirs[];
  static const std::string istr_ext;
  static const std::string istr_older;
  static const std::string vstr_older;
  static const std::string deferr;

  static const int stdBufSize       = 255;
  static const int iNDays           = 7;
  static const int maxExt           = 30;
  static const int minBaseDirLen    = 3;
  static const int minSubDirLen     = 1;
  static const int minRelFileAgeMax = 365;

  std::string basedir;
  std::string dirs[iNDays];
  std::string wildCards[maxExt];
  int numExt;
  int minRelFileAge;

  static bool instance;
  static Ini* sngl;
  
  Ini() : numExt(), minRelFileAge() {}

  Ini(const Ini&);
  Ini& operator=(const Ini&);


  bool chkS(const std::string& str) const;
  TCHAR* str2charry(const std::string& str, TCHAR* buffer) const;
  TCHAR* str2charry(const std::string& str, TCHAR* buffer, int n) const;
  bool GetPrivateProfileStringWerr(const std::string& appName, const std::string& keyName,
    std::string& returnedString, const std::string& fileName) const;
  bool fileExists(const std::string& fname);

public:

  static Ini* getInstance(); 
  ~Ini() {instance = false;}

  DWORD read(const std::string iniName, std::string& errex);
  void getBaseDir(std::string& baseDir) const;
  void getSubDirFromDayIndex(int didx, std::string& subDir) const;
  void getWildCard(int widx, std::string& wildCard) const;
  int getNumExts() const;
  int getMinRelFileAge() const;
  static int getNumberOfDays();
};

const std::string Ini::istr_basedir = basedir;
const std::string Ini::vstr_basedir = dir;
const std::string Ini::istr_subdirs = subdirs;
const std::string Ini::vstr_subdirs[] = {monday, tuesday, wednesday, thursday, friday, saturday, sunday};
const std::string Ini::istr_ext = ext;
const std::string Ini::istr_older = minrelage;
const std::string Ini::vstr_older = days;
const std::string Ini::deferr = :;

bool Ini::instance = false;
Ini* Ini::sngl = NULL;

Ini* Ini::getInstance()
{
  if(!instance)
  {
    sngl = new Ini();
    instance = true;
    return sngl;
  }
  else
    return sngl;
}

bool Ini::chkS(const std::string& str) const {
  if(str == deferr)
    return false;
  else return true;
}

TCHAR* Ini::str2charry(const std::string& str, TCHAR* buffer) const {
  if(buffer == NULL)
    return NULL;
  strcpy(buffer, str.c_str());
  return buffer;
}

TCHAR* Ini::str2charry(const std::string& str, TCHAR* buffer, int n) const {
  if(buffer == NULL)
    return NULL;
  strncpy(buffer, str.c_str(), n);
  return buffer;
}

bool Ini::GetPrivateProfileStringWerr(const std::string& appName, const std::string& keyName, std::string& returnedString, const std::string& fileName) const {
  TCHAR buf[stdBufSize];
  GetPrivateProfileString(appName.c_str(), keyName.c_str(), deferr.c_str(), str2charry(returnedString, buf), stdBufSize, fileName.c_str());
  returnedString = buf;
  return chkS(returnedString.c_str());
}

bool Ini::fileExists(const std::string& fname) {
  WIN32_FIND_DATA fileData;
  HANDLE hFind = FindFirstFile(fname.c_str(), &fileData);
  if(hFind == INVALID_HANDLE_VALUE)
    return false;
  else {
    FindClose(hFind);
    return true;
  }
}

DWORD Ini::read(const std::string iniName, std::string& errex) {

  if(!fileExists(iniName)) {
    errex = iniName;
    return ERROR_INI_OPEN;
  }

  // Basisverzeichnis auslesen
  if((GetPrivateProfileStringWerr(istr_basedir, vstr_basedir, basedir, iniName) == false) ||
    (basedir.size() < minBaseDirLen))
  {
    errex = istr_basedir;
    return ERROR_INI_SYN;
  }
  if(basedir[basedir.size()-1] !=->\\')
    basedir.append(\\);

  // Unterverzeichnisse auslesen
  for(int day = 0; day < iNDays; ++day) {
    if((GetPrivateProfileStringWerr(istr_subdirs, vstr_subdirs[day], dirs[day], iniName) == false) ||
      (dirs[day].size() < minSubDirLen))
    {
      errex = istr_subdirs;
      return ERROR_INI_SYN;
    }
    if(dirs[day][0] ==->\\')
      dirs[day] = dirs[day].substr(1);
    if(dirs[day][dirs[day].size()-1] ==->\\')
      dirs[day].resize(dirs[day].size()-1);
  }

  // Minimales Alter ist optional
  std::string ageStr;
  GetPrivateProfileStringWerr(istr_older, vstr_older, ageStr, iniName);
  if(chkS(ageStr)) {
    long l = strtol(ageStr.c_str(),->\0', 10);
    if(l>0 && l<minRelFileAgeMax)
      minRelFileAge = l;
  }

  // Extensions auslesen    
  numExt = 0;
  std::ostringstream oss;
  std::string curExt;
  for(int extnum = 1; extnum < maxExt; ++extnum) {
    oss << extnum;
    curExt = oss.str();
    oss.str();
    std::string ext;
    if(GetPrivateProfileStringWerr(istr_ext, curExt, ext, iniName) == false)
      break;
    else {
      wildCards[extnum-1] = *.;
      wildCards[extnum-1].append(ext);
      numExt++;
    }
  }

  // Mindestens eine Wildcard muss oben im Array abgelegt worden sein (*.txt etc.)
  if(!wildCards[0].empty())
    return ERROR_NONE;
  else {
    errex = istr_ext;
    return ERROR_INI_SYN;
  }
}

void Ini::getBaseDir(std::string& baseDir) const {
  baseDir = basedir;
}

void Ini::getSubDirFromDayIndex(int didx, std::string& subDir) const {
  subDir= dirs[didx];
}

void Ini::getWildCard(int widx, std::string& wildCard) const {
  wildCard = wildCards[widx]; 
}

int Ini::getNumExts() const {
  return numExt;
}

int Ini::getMinRelFileAge() const {
  return minRelFileAge;
}

int Ini::getNumberOfDays() {
  return iNDays;
}

//---------------------------------------------------
  
namespace datetime {
  time_t fileTimeToTime(const FILETIME* ft) {
    // Bed.: Zeit >= 1.1.1970, 00:00
    return (time_t) ((*(LONGLONG*)ft - 0x19DB1DED53E8000) / 10000000); 
  }

  time_t getCurTime() {
    return time(0);
  }

  int getLocalDayOfWeek() {
    time_t now = getCurTime(); 
    return localtime(&now)->tm_wday;
  }

  tm* getLocalTime() {
    time_t now = getCurTime(); 
    return localtime(&now);
  }
}

void showError(int errIdx, bool defTxt, bool extraTxt, const std::string* extra, bool lastErrorLookup) {
  if(defTxt)
    std::cout << errStrings[errIdx] << std::endl;
  if(extraTxt && (extra != NULL))
    std::cout << extra << std::endl;
  if(lastErrorLookup) {
    DWORD error = GetLastError();
    LPSTR error_msg; 
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 
      NULL, 
      error, 
      MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), 
      (LPTSTR) &error_msg, 
      0, 
      NULL); 

    std::cout << error_msg;
    LocalFree(error_msg); 
  }
  std::cout << std::endl;
}

//---------------------------------------------------

class BupDel {
public:
  struct Stats {
    tm *timeStarted, *timeCompleted;
    int nFiles, nFilesDeleted, nFilesError;
    Stats() : nFiles(), nFilesDeleted(), nFilesError(),
      timeStarted(0), timeCompleted(0) {}
    void clear() {
      nFiles = nFilesDeleted = nFilesError = 0;
      timeStarted = 0;
      timeCompleted = 0;
    }
  };

  BupDel(const Ini& ini_) : ini(ini_) {}

  void getStats(Stats& stats_) const;
  void showStats() const;
  int  traverseFiles(time_t curTime);
private:  
  Stats stats;
  const Ini& ini;

  void getTomorrowsSubDirName(std::string& dirName) const;    
  bool dirOrReadonly(DWORD fileAttributes, int& nFiles) const;
  void checkAndDelete(const WIN32_FIND_DATA& fileData, time_t curTime, const std::string& cplteDirName);
};

void BupDel::getStats(Stats& stats_) const {
  stats_ = stats;
}

void BupDel::showStats() const {
  char tbuf[50];
  std::cout << std::endl << *** BupDel Statistik **************** << std::endl << std::endl;
  strftime(tbuf, sizeof(tbuf), %H:%M:%S, stats.timeStarted);
  std::cout <<  Gestartet:  << tbuf << std::endl;
  strftime(tbuf, sizeof(tbuf), %H:%M:%S, stats.timeCompleted);
  std::cout <<  Beendet:    << tbuf << std::endl;
  std::cout <<  Anzahl der gefundenen Dateien:    << stats.nFiles << std::endl;
  std::cout <<  Anzahl der geloeschten Dateien:   << stats.nFilesDeleted << std::endl;
  std::cout <<  Anzahl der Fehler beim Loeschen:  << stats.nFilesError << std::endl;
  std::cout << ************************************* << std::endl << std::endl;
}

int BupDel::traverseFiles(time_t curTime) {

  stats.clear();
  stats.timeStarted = datetime::getLocalTime();

  std::string cplteDirName;
  ini.getBaseDir(cplteDirName);    
  std::string tsn;
  getTomorrowsSubDirName(tsn);
  cplteDirName.append(tsn + \\);
  std::string cplteWildName(cplteDirName + *.*);

  WIN32_FIND_DATA fileData;
  HANDLE hFind;
  hFind = FindFirstFile(cplteWildName.c_str(), &fileData);

  if (hFind == INVALID_HANDLE_VALUE) 
  {
    showError(ERROR_OPEN_TARGET_DIR, true, false, NULL, true);
    return ERROR_OPEN_TARGET_DIR;
  } else {

    BOOL found = TRUE;
    while(found) {

      if(!dirOrReadonly(fileData.dwFileAttributes, stats.nFiles)) {

        checkAndDelete(fileData, curTime, cplteDirName);

      }
      found = FindNextFile(hFind, &fileData);
    } 
    FindClose(hFind);
  }

  stats.timeCompleted = datetime::getLocalTime();
  return ERROR_NONE;
}

void BupDel::getTomorrowsSubDirName(std::string& dirName) const {
  int day = datetime::getLocalDayOfWeek();
  int delDay = day == ini.getNumberOfDays() ? 1 : day+1;
  ini.getSubDirFromDayIndex(delDay-1, dirName);
}

bool BupDel::dirOrReadonly(DWORD fileAttributes, int& nFiles) const {
  if(fileAttributes & FILE_ATTRIBUTE_DIRECTORY)
    return true;
  nFiles++;
  if (fileAttributes & FILE_ATTRIBUTE_READONLY)    
    return true;
  else
    return false;  
}

void BupDel::checkAndDelete(const WIN32_FIND_DATA& fileData, time_t curTime, const std::string& cplteDirName) {

  // Die in der INI-Datei angegebenen Extensions abklappern ...
  for(int nExt = 0; nExt < ini.getNumExts(); ++nExt) {

    // ... und vergleichen
    std::string wc;
    ini.getWildCard(nExt, wc);
    if(PathMatchSpec(fileData.cFileName, wc.c_str())) {

      // Alter der Datei berechnen, wenn nötig
      time_t ddays = 0;
      if(ini.getMinRelFileAge() > 0) {
        const time_t secPerDay = 86400;
        time_t diff = curTime - datetime::fileTimeToTime(&fileData.ftLastWriteTime);
        ddays = diff / secPerDay;
      }

      if(ddays >= ini.getMinRelFileAge()) {
        // Verzeichnis + Dateiname
        std::string fullName(cplteDirName);
        fullName.append(fileData.cFileName);

        // Datei löschen & Info ausgeben
        if(!DeleteFile(fullName.c_str())) {
          showError(ERROR_DEL_FILE, true, false, NULL, true);
          stats.nFilesError++;
        } else {
          std::cout << Datei  << fullName <<  geloescht. <<  // Alter:  << ddays <<  Tage << std::endl;
          stats.nFilesDeleted++;
        }
      }              
    }
  }
}

//---------------------------------------------------

int main(int argc[], char *argv[])
{  
  std::string iniName(argv[0]);
  iniName.resize(iniName.size()-3);
  iniName.append(ini);

  Ini* ini = Ini::getInstance();

  std::string exerr;
  DWORD error = ini->read(iniName, exerr);

  if(error != ERROR_NONE) {

    showError(error, true, true, &exerr, false);
 
 }  else {  

    BupDel bdel(*ini);

    if(bdel.traverseFiles(datetime::getCurTime()) == ERROR_NONE)
      bdel.showStats();

  }  
}

Ist aber nicht großartig getestet; Du solltest es eher als Beispiel ansehen. Die Formatierung wird wohl wieder ok sein, wenn Du alles in den Code-Editor kopierst. Arbeitest Du mit Visual C++ (weil hier ein paar Microsoft-spezifische Sachen drin sind)? Jedenfalls musst Du noch shlwapi.lib ins Projekt einbinden.
Und in die stdafx.h:

#define VC_EXTRALEAN
#include <windows.h>
#include <ctime>
#include <shlwapi.h>

Ach ja:
Es werden ein paar Daten aus einer INI-Datei gelesen (muss im gleichen Verzeichnis wie das Programm liegen und den gleichen Namen haben, Endung .ini statt .exe).

Code:
[BaseDir]
dir=P:\temp\test

[SubDirs]
monday=1-Montag
tuesday=2-Dienstag
wednesday=3-Mittwoch
thursday=4-Donnerstag
friday=5-Freitag
saturday=6-Samstag
sunday=7-Sonntag

[MinRelAge]
days=6

[ext]
1=txt
2=bla

MinRelAge ist optional (soll so eine Art Sicherheitsgurt sein: Wenn die Datei jünger ist als n Tage, wird sie nicht gelöscht). Unter [ext] kannst Du die Dateiendungen eintragen, der Rest ist sicher klar.

BTW: Da Bildschirmausgaben in Deinem Falls sicher nicht so sinnvoll sind, kannst Du die Ausgabe (im einfachsten Fall) in  eine Datei umleiten. In der Statistik (oder gleich am Anfang) sollte man dann noch das Datum ausgeben.

// Edit: da war ein Dreher bei den Monaten drin (wednesday <-> thursday)
 
Thema:

C++/C löschen von älteren Dateien

ANGEBOTE & SPONSOREN

Statistik des Forums

Themen
113.840
Beiträge
707.963
Mitglieder
51.494
Neuestes Mitglied
Flensburg45
Oben