注意:我目前只对C有深入的了解,但我参加了一个暑期课程,很快就会开始学习现代c++,所以c++ 20的方法也会非常有帮助。如果这是一个愚蠢的问题,或者已经有人问过了(我没有从谷歌上找到任何东西),那么链接也会很有帮助。
问题:
好的,假设我在设计一个程序。我想让程序打开一个文件,我可以告诉它确切的路径,或者把它放在我的工作目录中。为了便于示例,让我们在下面创建两条路径:
- (我的电脑路径)/project/partone/mainfiles/main.c
- (我电脑路径)/project/parttwo/mainfiles/data.csv
这通常不是问题,因为我可以给main.c提供data.csv的完整路径。但是如果我想发布程序呢?然后下载它的人在他们的计算机上会有一个不同的路径,自动使代码失败。
是否有办法在c++ 20(首选答案)和/或C99(如果你知道C99,至少给我一些关键词谷歌c++ 20,我听说C代码的大部分是可用于c++)。
我在想也许c++ 20中有一些包可以像"cd"命令,它可以从我所在的目录开始更改目录。比如告诉c++(从project/partone/mainfiles):
//pseudocode
cd ..
cd ..
cd parttwo
cd mainfiles
fopen data.csv
下面是一个小的辅助模块,用于获取可创建/可写目录的路径,用于保存程序数据。
appdata_path.hpp
#ifndef APPDATA_PATH_HPP
#define APPDATA_PATH_HPP
#include <filesystem>
#include <string>
std::filesystem::path
get_appdata_path( const std::string & application_name );
#endif
appdata_path.cpp
#include "appdata_path.hpp"
#ifdef _WIN32
#include <windows.h>
#include <shlobj.h>
#include <objbase.h>
#pragma comment(lib,"Shell32")
#pragma comment(lib,"Ole32")
std::filesystem::path
get_known_folder_path( REFKNOWNFOLDERID rfid )
{
wchar_t * p;
if (S_OK != SHGetKnownFolderPath( rfid, 0, NULL, &p )) return "";
std::filesystem::path result = p;
CoTaskMemFree( p );
return result;
}
std::filesystem::path
get_appdata_path( const std::string & application_name )
{
auto path = get_known_folder_path( FOLDERID_LocalAppData ); // or FOLDERID_RoamingAppData
if (!path.empty()) path /= application_name;
return path;
}
#else
#include <stdlib.h>
#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>
std::filesystem::path
get_appdata_path( const std::string & application_name )
{
const char * p = getenv( "HOME" );
if (p) return p + ("/" + application_name);
struct passwd * pw = getpwuid( getuid() );
if (pw) return pw->pw_dir + ("/" + application_name);
return "";
}
#endif
example.cpp
#include <iostream>
#include "appdata_path.hpp"
int main()
{
auto path = get_appdata_path( "Example Application" );
if (path.empty()) std::cout << "Wut?n";
else std::cout << path << "n";
}
指出:
注意,Windows代码在本地和漫游之间有一个选择。除非你打算让你的应用程序在多台计算机上运行,否则请使用Local。
文件名中某些字符无效(在Windows上)。一般来说,在命名文件时应该避免使用奇怪的字符,所以应该为应用程序使用一个简化的、文件系统友好的名称。正如您在示例中看到的那样,空格是可以的,但是是否使用它们取决于您。
请注意,代码除了返回一个有效路径之外什么都不做。它不创建或验证路径的存在性。你必须自己做这件事。
例如,要保存数据,您可以使用如下命令:
void save_data()
{
auto save_directory = get_appdata_path( "Quuxer" );
auto save_filename = save_directory / "data.csv";
if (save_directory.empty())
std::filesystem::create_directory( save_directory );
std::ofstream f( save_filename );
f << my_data;
}
此模块在Windows上按原样编译MSVC。如果你使用不同的编译器(GCC或LLVM/Clang),你需要显式地链接Shell32.lib
和Ole32.lib
。
它在Linux(和Mac也一样!)上按原样编译。
需要c++ 17,我想。