Opret midlertidig fil i C, MS Windows system

Indlæg af Hanne Mølgaard Plasc

Problem



Dybest set har jeg et program, der får en 4 meg komprimeret fil, den skal dekodes denne ukomprimerede ~ 100 meg, og komprimer den tilbage til ~ 4 meg fil. Jeg skal gemme denne mellemliggende 100 meg-fil et sted på drevet (vil ikke beholde det i hukommelsen).


Programmet er skrevet i C og vil blive udført på MS Windows 7. På tidspunktet for ukomprimering er der ikke givet nogen garanteret mappe (med skriveadgang) til programmet (mappen med kildefilen kan kun læses, og mappen med målfilen er muligvis ikke endnu specificeret).


Dette har vist sig ikke at være en nem opgave:


1) Jeg har læst om en C-funktion, der opretter en tempfil, der forsvinder, når lukket eller programmet afsluttes. Men fra det jeg forstår forsøger jeg at lave filen på disk C, i rodmappen, så det vil naturligvis mislykkes, hvis brugeren ikke har nogen rettigheder til det (hvilket normalt bruger ikke gør det)


2) Jeg havde en ide at bruge miljø/systemvariabel TEMP og lave en fil der, MEN ser på en tilfældig Win7 PC, der ikke var tweaked, ser jeg at denne variabel peger på c:/windows/temp, og den mappe har specifikke rettigheder for 'brugere' - det vil sige, de har rettigheder til at læse, udføre, oprette og skrive filer, men ikke at slette dem, kontrollere deres attributter mv. Det betyder, at jeg antager, at hvis programmet kører med brugernes privilegier, vil det kunne lave en fil, men ikke kunne slette den, så den eneste måde at 'slette' ville være at åbne filen for at skrive og derefter lukke den, hvilket gør det til en 0 længdefil. Dette er heller ikke ønsket, og jeg ved ikke, hvordan man spørger efter systemvariabler fra C


3) Så dybest set er kun idé jeg har lige nu at lave en funktion for at åbne filen, som:



  • forsøger at oprette en tempfil i output dir, hvis det er muligt

  • Hvis det mislykkes, forsøger du at oprette en tempfil i input dir

  • Hvis det mislykkes, forsøger du at oprette en tempfil i TEMP dir fra systemvariablen

  • Hvis det mislykkes, forsøger du at oprette en tempfil i TMP dir fra systemvariablen



og en sletningsfunktion, der:



  • forsøger at fjerne () filen (ved navn, der er gemt et sted)

  • Hvis den mislykkes, forsøger den at åbne filen til skrivning og lukke den, så den bliver en 0 byte fil



Er der bedre ideer?


Enhver hjælp er værdsat, tak!


PS: Programmet må ikke bruge eksterne biblioteker som MFC eller noget, kun indbyggede standart C-funktioner

Bedste reference


GetTempPath [4]



  Henter stien til den mappe, der er angivet til midlertidige filer.



GetTempFileName [5]



  Opretter et navn til en midlertidig fil. Hvis et unikt filnavn er
  genereres, en tom fil oprettes og håndtaget til det frigives
  ellers genereres kun et filnavn.



Disse to giver dig nem måde at få en placering og navn på en midlertidig fil.


UPD: Kodeeksempel på MSDN: Oprettelse og brug af en midlertidig fil. [6]

Andre referencer 1


#include <windows.h>
#include <iostream>
#include <chrono>
#include <string>
#include <cstdio>
#include <chrono>

using namespace std;

int FileExists(string& filepath)
{
  DWORD dwAttrib = GetFileAttributes(filepath.c\_str());
  return (dwAttrib != INVALID\_FILE\_ATTRIBUTES &&
         !(dwAttrib & FILE\_ATTRIBUTE\_DIRECTORY));
}

int GetTemporaryFilePath(
    string  filePrefix,
    string  fileExt,
    string& TmpFilePath /*return*/)
{
    if (fileExt[0] == '.')
        fileExt.erase(0,1);

    char TempPath[MAX\_PATH] = { 0 };

    if (!GetTempPath(MAX\_PATH, TempPath))
        return -1;

    uint16\_t tickint = 0;

    while(1) {
        const int nowlen = 17; char nowstr[nowlen];
        const int ticklen = 5; char tickstr[ticklen];

        // Milliseconds since 1970
        auto ms = chrono::duration\_cast<chrono::milliseconds>(
            chrono::system\_clock::now().time\_since\_epoch()
        );
        \_\_int64 nowint = ms.count();

        snprintf(nowstr,  nowlen,  "\%016" "I64" "x", nowint);
        snprintf(tickstr, ticklen, "\%04x", tickint);

        TmpFilePath = string(TempPath)
                    + filePrefix
                    + "."   + string(nowstr)
                    + "."   + string(tickstr)
                    + "."   + fileExt;

        if (!FileExists(TmpFilePath)) {
            //Touch File
            FILE* w = fopen(TmpFilePath.c\_str(), "w");
            fclose(w);
            break;
        }
        tickint++;
     }

     return 0;
}

int main()
{
    string TmpFilePath;
    GetTemporaryFilePath("MyFile", ".txt", TmpFilePath);
    cout << "TmpFilePath: " << TmpFilePath << endl;
    return 0;
}