Создать временный файл в системе C, MS Windows - PullRequest
6 голосов
/ 15 марта 2012

По сути, у меня есть программа, которая получает сжатый файл 4 Мб, она должна декодировать этот файл в несжатый ~ 100 Мб, а затем сжать его обратно в файл ~ 4 Мб. Мне нужно хранить этот промежуточный файл размером 100 мегабайт где-то на диске (не хочу хранить его в памяти).

Программа написана на C и будет выполняться на MS Windows 7. В момент распаковки программе не предоставляется гарантированная папка (с правом записи) (папка с исходным файлом может быть доступна только для чтения, а папка с целевым файлом). может быть еще не указано).

Это оказалось непростой задачей:

1) Я читал о функции C, которая создает временный файл, который исчезнет при закрытии или завершении программы. Тем не менее, насколько я понимаю, он пытается создать файл на диске C, в корневом каталоге, так что это, очевидно, завершится ошибкой, если у пользователя нет прав на это (чего нет у обычного пользователя)

2) У меня была идея использовать переменную среды / системы TEMP и создать там файл, НО, глядя на случайный ПК с Win7, который не был подстроен, я вижу, что эта переменная указывает на c: / windows / temp и эту папку имеет определенные права для «пользователей» - то есть у них есть права на чтение, выполнение, создание и запись файлов, но не на их удаление, проверку их атрибутов и т. д. Это означает, я предполагаю, что если программа запускается с правами пользователя , он сможет создать файл, но не сможет удалить его, поэтому единственный способ «удалить» это открыть файл для записи, а затем закрыть его, сделав его файлом нулевой длины. Это также нежелательно, и я не знаю, как запросить системные переменные из C

3) Итак, в принципе, единственная идея, которая у меня есть сейчас, - создать функцию для открытия файла, который:

  • пытается создать временный файл в выходном каталоге, если это возможно
  • в случае неудачи пытается создать временный файл во входном каталоге
  • в случае неудачи пытается создать временный файл в каталоге TEMP из системной переменной
  • в случае неудачи пытается создать временный файл в каталоге TMP из системной переменной

и функция удаления, которая:

  • пытается удалить () файл (по имени, которое где-то хранится)
  • в случае неудачи он пытается открыть файл для записи и закрыть его, чтобы он стал 0-байтовым файлом

Есть идеи получше?

Любая помощь приветствуется, спасибо!

PS: Программа не должна использовать какие-либо внешние библиотеки, такие как MFC или что-то в этом роде, только встроенные стандартные функции C

Ответы [ 2 ]

6 голосов
/ 15 марта 2012

GetTempPath

Извлекает путь к каталогу, предназначенному для временных файлов.

GetTempFileName

Создает имя для временного файла.Если генерируется уникальное имя файла, создается пустой файл и дескриптор к нему освобождается;в противном случае генерируется только имя файла.

Эти два предоставляют простой способ получения местоположения и имени для временного файла.

UPD: пример кода в MSDN: Создание и использование временного файла .

0 голосов
/ 20 сентября 2017
#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;
}
...