как получить системную или пользовательскую временную папку в unix и Windows?

#c

#c

Вопрос:

Я пишу проблему с C . Это должно работать как в ОС Windows, так и в ОС Unix.

Как получить пользовательскую или системную папку tmp в разных ОС?

Комментарии:

1. Не пишите больше проблем, у нас и так их достаточно. Напишите решение на этот раз. 🙂 Вам нужна фактическая временная папка или просто временный файл? В C нет понятия файловой системы, поэтому нет «папок», но вы можете использовать tmpfile or tmpnam для получения временного файла.

2. И в Windows эквивалентная функция GetTempFileName .

3. tmpfile Функция не дает вам имени; tmpnam функция дает вам имя, но не является безопасной (см. mkstemp() Которая дает вам как имя, так и дескриптор файла — и является безопасной).

4. @KerrekSB теперь cpp имеет en.cppreference.com/w/cpp/filesystem

Ответ №1:

Обновление: Спасибо @RoiDanton, самый актуальный ответ — std::filesystem::temp_directory_path (C 17)


Попробуйте boost::filesystem ‘s temp_directory_path() , который внутренне использует:

  • ISO / IEC 9945 (POSIX): путь, указанный первой переменной окружения, найденной в списке TMPDIR , TMP , TEMP , TEMPDIR "/tmp" . Если ни одна из них не найдена, __ANDROID__ или, если макрос, то определен, "/data/local/tmp"

  • Windows: путь, сообщаемый функцией Windows GetTempPath API.

Интересно, что Window GetTempPath использует логику, аналогичную версии POSIX: первая переменная среды в списке TMP , TEMP , USERPROFILE . Если ни одна из них не найдена, возвращается каталог Windows.

Тот факт, что эти методы в основном полагаются на переменные среды, кажется немного неприятным. Но, похоже, это определяется именно так. Видя, насколько это обыденно на самом деле, вы могли бы легко создать свою собственную, используя функцию cstdlib ‘s getenv , особенно если вам нужна конкретная расстановка приоритетов / требований или вы не хотите использовать другую библиотеку.

Комментарии:

1. Это лучший мультиплатформенный ответ, он должен быть принят.

2. Кроме того, с C 14 / C 17 это часть стандарта C : en.cppreference.com/w/cpp/filesystem/temp_directory_path

Ответ №2:

Используйте $TMPDIR переменную среды в соответствии с POSIX.

 char const *folder = getenv("TMPDIR");
if (folder == 0)
    folder = "/tmp";
  

Комментарии:

1. Однако при использовании переменной окружения есть всевозможные подводные камни. Они могут быть недоступны в определенных ситуациях с повышенными привилегиями или могут быть злонамеренно изменены злоумышленником (или по невнимательности)…

2. Да, есть проблемы с безопасностью, но я не знаю стандартной альтернативы, которая была бы более широко доступна. Вы могли бы (возможно, должны) создать защищенный подкаталог во временном каталоге (особенно, если значение равно /tmp ) для хранения файлов. Обратите внимание, что POSIX требует, чтобы, если в имени пути ‘указана символическая ссылка, mkdir(2) произошел сбой и для errno было установлено значение [EEXIST]’. Linux говорит, что mkdir(2) генерирует EEXIST, когда ‘имя пути уже существует (не обязательно в виде каталога). Сюда входит случай, когда pathname является символической ссылкой, висячей или нет.’ Таким образом, создание каталога безопасно.

3. TMP для Windows не TMPDIR

Ответ №3:

если вы используете QT (ядро), вы можете попробовать QString QDir::tempPath() или использовать его реализацию в своем коде (QT открыт, поэтому проверьте, как они это делают).

В документе сказано: В системах Unix / Linux это обычно /tmp ; в Windows это обычно путь в переменной окружения TEMP или TMP.

Ответ №4:

Согласно документам, максимальный путь равен MAX_PATH (260). Если путь окажется равным 260, код в приведенном выше примере (также plougy) завершится ошибкой, поскольку будет возвращен 261. Вероятно, размер буфера должен быть MAX_PATH 1.

 TCHAR szPath[MAX_PATH   1];
DWORD result = GetTempPath(MAX_PATH   1, szPath);
if (result != ERROR_SUCCESS) {
    // check GetLastError()
}   
  

Ответ №5:

Удобная функция :

 std::string getEnvVar( std::string const amp; key )
{
    char * val = getenv( key.c_str() );
    return val == NULL ? std::string("") : std::string(val);
}
  

Я предполагаю, что TEMP или что-то еще может быть передано в качестве аргумента? В зависимости от ОС, конечно. getenv является частью stdlib, поэтому он также должен быть переносимым.

Ответ №6:

Если вы получаете доступ к коду функции main (), может быть, лучше ввести необходимые имена папок через ** argv main () и использовать зависящий от ОС пакет запуска. Например, для UNIX

 bash a_launcher.sh
  

где a_launcher.sh это как

 ./a.out /tmp
  

Ответ №7:

В Windows: Используйте GetTempPath() для получения пути к каталогу, предназначенному для временных файлов.

 wstring TempPath;
wchar_t wcharPath[MAX_PATH];
if (GetTempPathW(MAX_PATH, wcharPath))
  TempPath = wcharPath;
  

Ответ №8:

Ни один из этих примеров не является действительно конкретным и не предоставляет рабочий пример (кроме std::filesystem::temp_directory_path), скорее они отсылают вас к документации Microsoft, вот рабочий пример с использованием «GetTempPath()» (протестировано в Windows 10):

 //temp.cpp
#include <iostream>
#include <windows.h>


int main()
{ 
    TCHAR path_buf[MAX_PATH];
    DWORD ret_val = GetTempPath(MAX_PATH, path_buf);
    if ( ret_val > MAX_PATH || (ret_val == 0) )
    {
        std::cout << "GetTempPath failed";
    } else {
        std::cout << path_buf;
    }
}
  

выводит:

 C:>temp.exe
C:UsersusernameAppDataLocalTemp