ฉันจะรับไดเรกทอรีที่โปรแกรมกำลังทำงานได้อย่างไร


269

มีวิธีที่ไม่เชื่อเรื่องพระเจ้าแพลตฟอร์มและระบบไม่เชื่อเรื่องพระเจ้าเพื่อให้ได้เส้นทางแบบเต็มของไดเรกทอรีจากที่โปรแกรมกำลังทำงานโดยใช้ C / C ++? เพื่อไม่ให้สับสนกับไดเรกทอรีการทำงานปัจจุบัน (โปรดอย่าแนะนำห้องสมุดเว้นแต่ว่าเป็นไลบรารีมาตรฐานเช่น clib หรือ STL)

(หากไม่มีวิธีการแพลตฟอร์ม / ระบบไม่เชื่อเรื่องพระเจ้าคำแนะนำที่ทำงานใน Windows และ Linux สำหรับระบบไฟล์ที่เฉพาะเจาะจงก็ยินดีต้อนรับเช่นกัน)


@ จักรกฤษ: นั่นคงจะเยี่ยมมาก (แม้ว่าปัญหานั้นมักไม่ได้เกิดขึ้นใน Windows)
Ashwin Nanjappa

2
ถ้าคุณไม่สามารถแยกเส้นทางจากที่เชื่อถือได้argv[0]เทคนิคจะขึ้นอยู่กับระบบปฏิบัติการมาก
David R Tribble

1
เพียงชี้แจง: 'ไดเรกทอรีปัจจุบัน' หรือ 'ไดเรกทอรีที่โปรแกรมกำลังเรียกใช้จาก' (ในคำศัพท์ของคำถาม) คือไดเรกทอรีที่มีไฟล์รูปภาพของโปรแกรม (~ .exe file) อยู่และ ' ไดเรกทอรีการทำงานปัจจุบัน' เป็นไดเรกทอรีที่มีการเติมข้อความอัตโนมัติหากโปรแกรมใช้เส้นทางสัมพัทธ์?
colemik

3
เมื่อคุณ#include <windows.h>Windows จะทำให้ไปยังเส้นทางที่ปฏิบัติการในchar* _pgmptrคุณไม่จำเป็นต้องเรียกใช้ฟังก์ชั่นพิเศษหรือรับขยะถ้าคุณทำงานบน Windows เท่านั้น
rsethc

1
_pgmptrแม้ว่าความคิดเห็นจากสามปีที่ผ่านมาผมต้องการที่จะขยายตัวในการแสดงความคิดเห็นเกี่ยวกับ rsethc เอกสารประกอบของ MSDN ระบุว่าตัวแปร_pgmptrและ_wpgmptrเลิกใช้แล้วและคุณควรใช้ฟังก์ชั่น_get_pgmptr(char**)หรือ_get_wpgmptr(wchar_t**)แทน MSDN
Hydranix

คำตอบ:


181

นี่คือรหัสเพื่อรับเส้นทางแบบเต็มไปยังแอปที่กำลังดำเนินการ:

ของ windows:

int bytes = GetModuleFileName(NULL, pBuf, len);
return bytes ? bytes : -1;

ลินุกซ์:

int bytes = MIN(readlink("/proc/self/exe", pBuf, len), len - 1);
if(bytes >= 0)
    pBuf[bytes] = '\0';
return bytes;

3
ฉันคิดว่านี่เป็นคำตอบเดียวที่นี่ที่ตอบคำถามและทำเพื่อทั้ง Windows และ Linux งานที่ดี.
Frank Szczerba

6
Boo for / proc / pid / exe - ไม่รองรับบน OS X ด้วยเหตุผลบางประการ
คริสลัทซ์

24
เมื่อฉันเห็นรหัสที่ดู/procส่วนหนึ่งของฉันตายไปเล็กน้อย โลกทั้งใบไม่ใช่ลินุกซ์และแม้กระทั่งในแพลตฟอร์มเดียวที่/procควรได้รับการพิจารณาว่ามีการเปลี่ยนแปลงจากรุ่นหนึ่งไปยังอีกรุ่นเป็นรุ่นใหญ่เป็นรุ่นล่าสุด
asveikau

4
หากพวกเขาเปิดใช้คำสั่ง aliased บน Linux เป็น argv [0] "ชื่อของคำสั่ง" หรือขยาย?
Andy Dent

20
วิธีการเกี่ยวกับการเพิ่มchar pBuf[256]; size_t len = sizeof(pBuf);เพื่อให้การแก้ปัญหาชัดเจนยิ่งขึ้น
charles.cc.hsu

166

หากคุณดึงข้อมูลไดเรกทอรีปัจจุบันเมื่อโปรแกรมเริ่มทำงานครั้งแรกแสดงว่าคุณมีไดเรกทอรีที่โปรแกรมของคุณเริ่มทำงานอย่างมีประสิทธิภาพ เก็บค่าไว้ในตัวแปรและอ้างอิงในภายหลังในโปรแกรมของคุณ นี่คือความแตกต่างจากไดเรกทอรีที่เก็บไฟล์โปรแกรมปฏิบัติการปัจจุบัน ไม่จำเป็นต้องเป็นไดเรกทอรีเดียวกัน หากมีคนรันโปรแกรมจากพรอมต์คำสั่งแสดงว่าโปรแกรมกำลังรันจากไดเร็กทอรีการทำงานปัจจุบันของพรอมต์คำสั่งแม้ว่าไฟล์โปรแกรมจะอยู่ที่อื่น

getcwd เป็นฟังก์ชั่น POSIX และได้รับการสนับสนุนนอกกรอบโดยแพลตฟอร์มที่รองรับ POSIX ทั้งหมด คุณไม่จำเป็นต้องทำอะไรเป็นพิเศษ (นอกเหนือจากการรวมส่วนหัวขวา unistd.h บน Unix และ direct.h บน windows)

เนื่องจากคุณกำลังสร้างโปรแกรม C มันจะเชื่อมโยงกับไลบรารีเวลาทำงาน c เริ่มต้นซึ่งเชื่อมโยงกับกระบวนการทั้งหมดในระบบ (หลีกเลี่ยงข้อยกเว้นที่สร้างขึ้นเป็นพิเศษ) และจะรวมฟังก์ชันนี้เป็นค่าเริ่มต้น CRT นั้นไม่เคยถูกพิจารณาว่าเป็นไลบรารีภายนอกเพราะมันจะให้ส่วนต่อประสานที่สอดคล้องกับมาตรฐานขั้นพื้นฐานกับระบบปฏิบัติการ

ในฟังก์ชั่น windows getcwd ได้รับการคัดค้าน _getcwd ฉันคิดว่าคุณสามารถใช้มันในแบบนี้

#include <stdio.h>  /* defines FILENAME_MAX */
#ifdef WINDOWS
    #include <direct.h>
    #define GetCurrentDir _getcwd
#else
    #include <unistd.h>
    #define GetCurrentDir getcwd
 #endif

 char cCurrentPath[FILENAME_MAX];

 if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath)))
     {
     return errno;
     }

cCurrentPath[sizeof(cCurrentPath) - 1] = '\0'; /* not really required */

printf ("The current working directory is %s", cCurrentPath);

44
คำตอบที่ดี แต่ฉันคิดว่า "ไดเรกทอรีการทำงานปัจจุบัน" ไม่ใช่สิ่งที่ต้องการ
Michael Burr

4
คุณควรเพิ่มว่าแม้ว่าเอกสารบางคนบอกว่า cCurrentpath ที่สามารถเป็นโมฆะและจะได้รับการจัดสรรโดย getcwd getcwd ดูเหมือนจะไม่จัดสรรบางสิ่งบางอย่างบน Mac OS และเงียบเกิดปัญหาโปรแกรมของคุณ
Janusz

4
มีข้อผิดพลาดเล็ก ๆ แต่น่าเสียดายที่ฉันไม่สามารถแก้ไขยัง .. บรรทัด 10: cCurrentpath: ควรจะ cCurrentPath
Lipis

8
IMO บน Windows ควรใช้ฟังก์ชันที่มีชื่อ POSIX (ซึ่งบางอันเริ่มต้นด้วยเครื่องหมายขีดล่าง) ควรหลีกเลี่ยง พวกเขาไม่ใช่ Windows API ที่แท้จริง แต่เป็น CRT Windows API ที่คุณต้องการใช้คือ GetCurrentDirectory () msdn.microsoft.com/en-us/library/aa364934(VS.85).aspx
asveikau

6
คำตอบของไมค์ถูกต้อง "ไดเรกทอรีปัจจุบัน" ไม่เหมือนกับไดเรกทอรีที่ใช้งานอยู่เสมอ เช่นหากแอปทำงานเป็นบริการบน Windows ไดเรกทอรีปัจจุบันอาจจะเป็น C: \ Windows \ System32 ในขณะที่ไบนารี dir นั้นแตกต่างกัน
ลัคกี้ลุค

42

นี่คือจากฟอรัม cplusplus

บน windows:

#include <string>
#include <windows.h>

std::string getexepath()
{
  char result[ MAX_PATH ];
  return std::string( result, GetModuleFileName( NULL, result, MAX_PATH ) );
}

บน Linux:

#include <string>
#include <limits.h>
#include <unistd.h>

std::string getexepath()
{
  char result[ PATH_MAX ];
  ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX );
  return std::string( result, (count > 0) ? count : 0 );
}

ใน HP-UX:

#include <string>
#include <limits.h>
#define _PSTAT64
#include <sys/pstat.h>
#include <sys/types.h>
#include <unistd.h>

std::string getexepath()
{
  char result[ PATH_MAX ];
  struct pst_status ps;

  if (pstat_getproc( &ps, sizeof( ps ), 0, getpid() ) < 0)
    return std::string();

  if (pstat_getpathname( result, PATH_MAX, &ps.pst_fid_text ) < 0)
    return std::string();

  return std::string( result );
}

1
โซลูชัน Windows นั้นจะไม่จัดการอักขระที่ไม่ใช่ ANSI ในเส้นทาง คุณอาจใช้ GetModuleFileNameW และแปลงเป็น UTF-8 อย่างชัดเจน (โปรดระมัดระวังในการแปลงกลับเมื่อใดก็ตามที่คุณต้องการใช้คำสั่งระบบไฟล์)
Adrian McCarthy

3
สำหรับวิธีการแก้ปัญหา Windows ฉันได้รับข้อผิดพลาดerror: cannot convert 'char*' to 'LPWCH {aka wchar_t*}' for argument '2' to 'DWORD GetModuleFileNameW(HMODULE, LPWCH, DWORD)'เมื่อรวบรวมกับ MinGW
HelloGoodbye

2
@ เอเดรียนฉันไม่ได้เป็นโปรแกรมเมอร์ของ windows แต่ไม่มี DEFINE หรือ someway ที่จะบอกคอมไพเลอร์ของคุณให้ใช้ _W () ฟังก์ชั่นการทำงานอัตโนมัติ
Octopus

1
@Octopus: หากต้องการใช้การโทรแบบกว้างคุณจะต้องใช้ WCHAR (แทนที่จะเป็นถ่าน) และ std :: wstring (แทน std :: string)
Adrian McCarthy

29

หากคุณต้องการวิธีมาตรฐานที่ไม่มีไลบรารี: ไม่แนวคิดทั้งหมดของไดเรกทอรีไม่รวมอยู่ในมาตรฐาน

ถ้าคุณยอมรับว่าบางคน (แบบพกพา) พึ่งพา lib ใกล้มาตรฐานคือโอเค: ใช้ห้องสมุดระบบแฟ้ม Boost ของและขอinitial_path ()

IMHO ใกล้เคียงที่สุดเท่าที่คุณจะทำได้ด้วยกรรมที่ดี (Boost เป็นชุดห้องสมุดคุณภาพสูงที่ได้รับการยอมรับอย่างดี)


8
จาก Boost docs: เทมเพลต <class Path> const Path & initial_path (); คืนค่า: current_path () ณ เวลาที่เข้าสู่ main () และ current_path () คือ 'ราวกับว่าโดย POSIX getcwd ()' นี่ไม่ใช่สิ่งที่ผู้ถามร้องขอ
Jonathan Leffler

ดูboost.org/doc/libs/1_46_1/libs/filesystem/v3/doc/...สำหรับการเพิ่ม 1.46.1
Moala

ตามที่แสดงความคิดเห็นสิ่งนี้จะให้เส้นทางจากการที่ไบนารีถูกเรียกไม่ใช่เส้นทางไปยังไบนารี ... เนื่องจากสามารถเริ่มต้นจากโฟลเดอร์อื่น
jpo38

21

Filesystem TS เป็นมาตรฐาน (และสนับสนุนโดย gcc 5.3+ และ clang 3.9+) ดังนั้นคุณจึงสามารถใช้current_path()ฟังก์ชันได้:

std::string path = std::experimental::filesystem::current_path();

ใน gcc (5.3+) เพื่อรวมระบบไฟล์ที่คุณต้องใช้:

#include <experimental/filesystem>

และเชื่อมโยงรหัสของคุณด้วยการ-lstdc++fsตั้งค่าสถานะ

หากคุณต้องการที่จะใช้ระบบแฟ้มกับ Microsoft Visual Studio แล้วอ่านหนังสือเล่มนี้


6
จากลิงก์อ้างอิง1-2) Returns the absolute path of the current working directory, obtained as if by POSIX getcwd. (2) returns path() if error occurs. Downvoted เนื่องจาก OP จะสอบถามเกี่ยวกับเส้นทางปัจจุบันของไฟล์ที่เรียกทำงานได้มากกว่าไดเรกทอรีทำงานปัจจุบัน
S. Saad

20

ฉันรู้ว่ามันสายเกินไปที่จะตอบคำถามในวันนี้ แต่ฉันพบว่าไม่มีคำตอบใดที่เป็นประโยชน์กับฉันเช่นเดียวกับวิธีการแก้ปัญหาของฉันเอง วิธีที่ง่ายมากในการรับเส้นทางจาก CWD ไปยังโฟลเดอร์ bin ของคุณเป็นดังนี้:

int main(int argc, char* argv[])
{
    std::string argv_str(argv[0]);
    std::string base = argv_str.substr(0, argv_str.find_last_of("/"));
}

ตอนนี้คุณสามารถใช้สิ่งนี้เป็นฐานสำหรับเส้นทางญาติของคุณ ตัวอย่างเช่นฉันมีโครงสร้างไดเรกทอรีนี้:

main
  ----> test
  ----> src
  ----> bin

และฉันต้องการรวบรวมซอร์สโค้ดของฉันไปยังถังขยะและเขียนบันทึกเพื่อทดสอบฉันสามารถเพิ่มบรรทัดนี้ลงในรหัสของฉันได้

std::string pathToWrite = base + "/../test/test.log";

ฉันได้ลองวิธีนี้บน Linux โดยใช้ full path, alias และอื่น ๆ และใช้งานได้ดี

บันทึก:

หากคุณอยู่บน windows คุณควรใช้ '\' เป็นตัวคั่นไฟล์ไม่ใช่ '/' คุณจะต้องหลบหนีสิ่งนี้เช่นกัน:

std::string base = argv[0].substr(0, argv[0].find_last_of("\\"));

ฉันคิดว่าสิ่งนี้ควรใช้งานได้ แต่ยังไม่ได้ทดสอบดังนั้นความคิดเห็นจะได้รับการชื่นชมถ้าใช้งานได้หรือแก้ไขไม่ได้


ใช่มันทำงานบน Windows ได้เช่นกัน ฉันคิดว่านั่นเป็นทางออกที่ดีที่สุด เท่าที่ฉันรู้ argv [0] จะเก็บพา ธ ไปยัง executable เสมอ
Wodzu

4
argv[0]เป็นความคิดที่ดีมาก แต่โชคไม่ดีที่ฉันได้รับบน Linux คือ "./my_executable_name" หรือ "./make/my_executable_name" โดยพื้นฐานแล้วสิ่งที่ฉันได้รับนั้นขึ้นอยู่กับว่าฉันเปิดตัวมันอย่างไร
Xeverous

@ Xeverous: งั้นเหรอ? หากฉันมีไฟล์บางไฟล์ที่สัมพันธ์กับไฟล์สั่งการของฉันที่ต้องเปิดให้เริ่มจาก "./" หรือ "./make/" ในกรณีของคุณควรใช้งานได้ "" เป็นไดเรกทอรีการทำงานในปัจจุบันและ argv [0] จะบอกเส้นทางสัมพัทธ์กับไฟล์ปฏิบัติการจากที่นั่นซึ่งเป็นสิ่งที่ OP ต้องการ ในกรณีใด ๆ สิ่งที่ฉันต้องการ
nilo

9

ไม่ไม่มีวิธีมาตรฐาน ฉันเชื่อว่ามาตรฐาน C / C ++ ไม่ได้พิจารณาถึงการมีอยู่ของไดเรกทอรี (หรือองค์กรระบบไฟล์อื่น ๆ )

หน้าต่างGetModuleFileName ()จะกลับเส้นทางแบบเต็มไปยังแฟ้มที่ปฏิบัติการของกระบวนการปัจจุบันเมื่อhModuleพารามิเตอร์ถูกตั้งค่าให้เป็นโมฆะ ฉันไม่สามารถช่วยด้วย Linux

นอกจากนี้คุณควรชี้แจงว่าคุณต้องการไดเรกทอรีปัจจุบันหรือไดเรกทอรีที่อิมเมจโปรแกรม / ปฏิบัติการอยู่ คำถามของคุณค่อนข้างชัดเจนในจุดนี้


9

บน Windows วิธีที่ง่ายที่สุดคือการใช้_get_pgmptrฟังก์ชั่นในstdlib.hการรับตัวชี้ไปยังสตริงซึ่งแสดงถึงพา ธ สัมบูรณ์ไปยังไฟล์ที่เรียกทำงานได้รวมถึงชื่อไฟล์ที่เรียกใช้งานได้

char* path;
_get_pgmptr(&path);
printf(path); // Example output: C:/Projects/Hello/World.exe

8

อาจจะรวมไดเรกทอรีทำงานปัจจุบันกับ argv [0]? ฉันไม่แน่ใจว่าจะใช้งานได้ใน Windows หรือไม่ แต่ใช้งานได้ใน linux

ตัวอย่างเช่น:

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char **argv) {
    char the_path[256];

    getcwd(the_path, 255);
    strcat(the_path, "/");
    strcat(the_path, argv[0]);

    printf("%s\n", the_path);

    return 0;
}

เมื่อเรียกใช้มันจะแสดงผล:

jeremy @ jeremy-desktop: ~ / Desktop $ ./test
/home/jeremy/Desktop/./test


คุณจะต้องตรวจสอบเพื่อดูว่าเส้นทางที่แน่นอนจะได้รับใน argv [0] แต่ที่สำคัญกว่านั้นจะเป็นเช่นไรหากภาพนั้นตั้งอยู่ในเส้นทาง PATH? linux กรอกข้อมูลในพา ธ แบบเต็มหรือมีอะไรบ้างในบรรทัดคำสั่ง?
Michael Burr

ดังที่ Mike B ชี้ให้เห็นว่าเป็นวิธีการที่ไม่ทั่วไป ใช้งานได้ในบางสถานการณ์ที่ จำกัด มากเท่านั้น โดยทั่วไปเฉพาะเมื่อคุณเรียกใช้คำสั่งด้วยชื่อพา ธ แบบสัมพัทธ์ - และมันก็ไม่ได้สวยงามเมื่อคุณเรียกใช้ ../../../bin/progname แทนที่จะเป็น. / การทดสอบ
Jonathan Leffler

หากคุณแก้ไขเส้นทางสัมพัทธ์ที่เป็นไปได้ของ argv [0] เทียบกับไดเรกทอรีปัจจุบัน (เพราะ argv [0] อาจเป็น "../../myprogram.exe") นั่นอาจเป็นวิธีที่ปลอดภัยที่สุดในการตอบคำถาม มันจะใช้งานได้เสมอและพกพาได้ (มันสามารถใช้งานบน Android ได้!)
jpo38

7

สำหรับ Win32 GetCurrentDirectoryควรทำเคล็ดลับ


มีจับขนาดใหญ่ที่มีฟังก์ชั่นนี้ : การใช้งานแบบมัลติเธรดและใช้ร่วมกันรหัสห้องสมุดไม่ควรใช้ฟังก์ชั่น GetCurrentDirectory และควรหลีกเลี่ยงการใช้ pathnames หากคุณสามารถทำงานกับสมมติฐานนี้ได้มากกว่าทางออกที่ดีที่สุด
McLeary

6

คุณไม่สามารถใช้ argv [0] เพื่อจุดประสงค์นั้นโดยปกติจะมีเส้นทางแบบเต็มไปยังไฟล์ที่เรียกใช้งานได้ แต่ไม่จำเป็นต้องทำ - กระบวนการนั้นสามารถสร้างขึ้นได้ด้วยค่าที่กำหนดเองในฟิลด์

นอกจากนี้โปรดทราบว่าไดเรกทอรีปัจจุบันและไดเรกทอรีที่มีไฟล์ปฏิบัติการนั้นมีสองสิ่งที่แตกต่างกันดังนั้น getcwd () จะไม่ช่วยคุณเช่นกัน

บน Windows ใช้ไฟล์ GetModuleFileName () บน Linux read / dev / proc / procID / ..


3

เพียงเพื่อจะกองอยู่ที่นี่ ...

ไม่มีวิธีการแก้ปัญหามาตรฐานเพราะภาษามีความไม่เชื่อเรื่องพระเจ้าของระบบไฟล์พื้นฐานดังนั้นอย่างที่คนอื่น ๆ พูดถึงแนวคิดของระบบไฟล์ที่ใช้ไดเรกทอรีอยู่นอกขอบเขตของภาษา c / c ++

นอกเหนือจากนั้นคุณไม่ต้องการไดเรกทอรีการทำงานปัจจุบัน แต่ไดเรกทอรีที่โปรแกรมกำลังทำงานอยู่ซึ่งต้องคำนึงถึงวิธีที่โปรแกรมไปถึงที่ที่มันอยู่ - คือมันวางไข่เป็นกระบวนการใหม่ผ่านทางแยกเป็นต้น เพื่อให้ไดเร็กตอรี่มีโปรแกรมทำงานอยู่, ดังที่วิธีแก้ปัญหาที่แสดง, ต้องการให้คุณรับข้อมูลนั้นจากโครงสร้างการควบคุมกระบวนการของระบบปฏิบัติการที่เป็นปัญหา, ซึ่งเป็นสิทธิ์เฉพาะของคำถามนี้ ดังนั้นตามคำนิยามมันเป็นโซลูชั่นเฉพาะของระบบปฏิบัติการ


3

สำหรับระบบ Windows ที่คอนโซลคุณสามารถใช้dirคำสั่งsystem ( ) และคอนโซลให้ข้อมูลเกี่ยวกับไดเรกทอรีและอื่น ๆ อ่านเกี่ยวกับคำสั่งที่dir cmdแต่สำหรับระบบที่คล้าย Unix ฉันไม่รู้ว่า ... หากคำสั่งนี้รันให้อ่านคำสั่ง bash lsไม่แสดงไดเรกทอรี ...

ตัวอย่าง:

int main()
{
    system("dir");
    system("pause"); //this wait for Enter-key-press;
    return 0;
}

2
#include <windows.h>
using namespace std;

// The directory path returned by native GetCurrentDirectory() no end backslash
string getCurrentDirectoryOnWindows()
{
    const unsigned long maxDir = 260;
    char currentDir[maxDir];
    GetCurrentDirectory(maxDir, currentDir);
    return string(currentDir);
}

1

บนแพลตฟอร์ม POSIX คุณสามารถใช้getcwd ()

บน Windows คุณอาจใช้_getcwd ()เนื่องจากการใช้getcwd ()ได้ถูกเลิกใช้แล้ว

สำหรับไลบรารีมาตรฐานถ้า Boost เป็นมาตรฐานเพียงพอสำหรับคุณฉันจะแนะนำระบบไฟล์ Boost :: แต่ดูเหมือนว่าพวกเขาจะลบเส้นทางการทำให้เป็นมาตรฐานออกจากข้อเสนอ คุณอาจต้องรอจนกว่าTR2 จะพร้อมใช้งานสำหรับโซลูชันมาตรฐานอย่างสมบูรณ์


10
getcwd () ไม่ทำสิ่งที่ผู้ถามถาม
Jonathan Leffler

ไม่ใช่ว่าคำตอบที่ยอมรับนั้นใช้ getcwd () หรือฉันไม่เพียงแค่เข้าใจเท่านั้น?
Sнаđошƒаӽ

ฉันโหวตเพราะคุณเป็นคนที่มาพร้อมกับสิ่งที่ถือว่าเป็นคำตอบที่ถูกต้องก่อน
Arnaud

คำตอบนี้ไม่แม้แต่จะพยายามตอบคำถาม ความอัปยศในการเขียนมัน
HelloWorld

1

สำหรับเส้นทางญาตินี่คือสิ่งที่ฉันทำ ฉันรู้อายุของคำถามนี้ฉันเพียงต้องการมีส่วนร่วมตอบง่ายกว่าที่ทำงานในกรณีส่วนใหญ่:

สมมติว่าคุณมีเส้นทางเช่นนี้:

"path/to/file/folder"

ด้วยเหตุผลบางอย่างไฟล์สั่งการที่สร้างโดย Linux ซึ่งทำงานใน eclipse นั้นใช้ได้ดีกับสิ่งนี้ อย่างไรก็ตาม windows จะสับสนมากหากได้รับเส้นทางเช่นนี้เพื่อทำงานกับ!

ตามที่ระบุไว้ข้างต้นมีหลายวิธีในการรับพา ธ ปัจจุบันไปยังไฟล์ที่เรียกใช้งานได้ แต่วิธีที่ง่ายที่สุดที่ฉันพบว่ามีเสน่ห์ในกรณีส่วนใหญ่คือการผนวกสิ่งนี้กับส่วนหน้าของเส้นทางของคุณ:

"./path/to/file/folder"

เพียงเพิ่ม "./" คุณควรจะได้รับการจัดเรียง! :) จากนั้นคุณสามารถเริ่มต้นการโหลดจากไดเรกทอรีใด ๆ ที่คุณต้องการตราบใดที่มันอยู่กับตัวปฏิบัติการ

แก้ไข: มันจะไม่ทำงานถ้าคุณพยายามที่จะเปิดใช้งานการปฏิบัติการจากรหัส :: บล็อกถ้านั่นคือสภาพแวดล้อมการพัฒนาที่มีการใช้งานด้วยเหตุผลบางอย่างรหัส :: บล็อกไม่ได้โหลดสิ่งที่ถูกต้อง ... : D

EDIT2: สิ่งใหม่ที่ฉันได้พบคือถ้าคุณระบุเส้นทางแบบคงที่เช่นนี้ในรหัสของคุณ (สมมติว่า Example.data เป็นสิ่งที่คุณต้องโหลด):

"resources/Example.data"

หากคุณเปิดแอพจากไดเรกทอรีจริง (หรือใน Windows คุณจะสร้างทางลัดและตั้งค่า dir ที่ใช้งานให้เป็น dir ของแอพ) จากนั้นมันจะทำงานเช่นนั้น โปรดระลึกไว้เสมอเมื่อทำการดีบั๊กปัญหาเกี่ยวกับพา ธ ของทรัพยากร / ไฟล์ที่หายไป (โดยเฉพาะอย่างยิ่งใน IDEs ที่ตั้งค่า dir ทำงานไม่ถูกต้องเมื่อเรียกใช้ build exe จาก IDE)


1

วิธีแก้ไขปัญหาห้องสมุด (แม้ว่าฉันรู้ว่าสิ่งนี้ไม่ได้ถูกถาม) หากคุณใช้ Qt: QCoreApplication::applicationDirPath()


1

แค่สองเซ็นต์ของฉัน แต่รหัสต่อไปนี้ไม่สามารถใช้งานได้ใน C ++ 17 ใช่ไหม

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main(int argc, char* argv[])
{
    std::cout << "Path is " << fs::path(argv[0]).parent_path() << '\n';
}

ดูเหมือนว่าจะทำงานให้ฉันบน Linux อย่างน้อย

จากความคิดก่อนหน้านี้ฉันมี:

std::filesystem::path prepend_exe_path(const std::string& filename, const std::string& exe_path = "");

ด้วยการใช้งาน:

fs::path prepend_exe_path(const std::string& filename, const std::string& exe_path)
{
    static auto exe_parent_path = fs::path(exe_path).parent_path();
    return exe_parent_path / filename;
}

และเคล็ดลับการเริ่มต้นในmain():

(void) prepend_exe_path("", argv[0]);

ขอบคุณ @Sam Redway สำหรับแนวคิด argv [0] และแน่นอนฉันเข้าใจว่า C ++ 17 นั้นไม่ได้อยู่เป็นเวลาหลายปีเมื่อ OP ถามคำถาม


0

เพิ่มประสิทธิภาพของระบบไฟล์initial_path()เช่น POSIX getcwd()และไม่ทำสิ่งที่คุณต้องการด้วยตัวเอง แต่การผนวกargv[0]เข้ากับสิ่งใดสิ่งหนึ่งก็ควรทำ

คุณอาจทราบว่าผลลัพธ์นั้นไม่สวยเสมอไป - คุณอาจได้รับสิ่งที่ชอบ/foo/bar/../../baz/a.outหรือ/foo/bar//baz/a.outแต่ฉันเชื่อว่ามันมักจะส่งผลในเส้นทางที่ถูกต้องซึ่งตั้งชื่อไฟล์เรียกใช้งานได้

ก่อนหน้านี้ฉันเคยเขียนวิธีใช้envp(อาร์กิวเมนต์ที่สามmain()ซึ่งทำงานบน Linux แต่ไม่สามารถใช้งานได้บน Windows ดังนั้นฉันจึงแนะนำวิธีการแก้ปัญหาแบบเดียวกับที่คนอื่นทำก่อนหน้านี้ แต่มีคำอธิบายเพิ่มเติมว่าทำไมมันถูกต้องจริง แม้ว่าผลลัพธ์จะไม่สวย


0

ในฐานะที่เป็นMinokกล่าวไม่มีการทำงานดังกล่าวระบุมาตรฐาน C INI หรือ C ++ มาตรฐาน นี่ถือเป็นคุณลักษณะเฉพาะระบบปฏิบัติการอย่างแท้จริงและมีการระบุไว้ในมาตรฐาน POSIX เป็นต้น

Thorsten79ได้ให้คำแนะนำที่ดีมันเป็นห้องสมุด Boost.Filesystem อย่างไรก็ตามมันอาจจะไม่สะดวกในกรณีที่คุณไม่ต้องการให้มีการพึ่งพาลิงค์เวลาใด ๆ ในรูปแบบไบนารีสำหรับโปรแกรมของคุณ

ทางเลือกที่ดีที่ฉันอยากจะแนะนำคือชุดของไลบรารี STLSoft C ++ เฉพาะส่วนหัว 100% Matthew Wilson (ผู้เขียนหนังสือที่ต้องอ่านเกี่ยวกับ C ++) มี facade แบบพกพา PlatformSTL ให้การเข้าถึง API เฉพาะระบบ: WinSTL สำหรับ Windows และ UnixSTL บน Unix ดังนั้นจึงเป็นโซลูชันแบบพกพา องค์ประกอบเฉพาะของระบบทั้งหมดจะถูกระบุด้วยการใช้คุณลักษณะและนโยบายดังนั้นจึงเป็นเฟรมเวิร์กที่ขยายได้ แน่นอนว่ามีระบบไฟล์ของห้องสมุด


0

คำสั่ง linux bash ซึ่ง progname จะรายงานพา ธ ไปยังโปรแกรม

แม้ว่าจะมีใครสามารถออกคำสั่ง which จากภายในโปรแกรมของคุณและนำเอาท์พุทไปยังไฟล์ tmp และในเวลาต่อมาโปรแกรมอ่านไฟล์ tmp นั้นมันจะไม่บอกคุณว่าโปรแกรมนั้นเป็นหนึ่งในการดำเนินการหรือไม่ มันจะบอกคุณว่าโปรแกรมที่มีชื่อนั้นอยู่ที่ไหน

สิ่งที่จำเป็นคือการขอรับหมายเลข id กระบวนการของคุณและแยกวิเคราะห์เส้นทางไปยังชื่อ

ในโปรแกรมของฉันฉันต้องการทราบว่าโปรแกรมถูกเรียกใช้งานจากไดเรกทอรีช่องเก็บของผู้ใช้หรือจากส่วนอื่นในพา ธ หรือจาก / usr / bin / usr / bin จะมีรุ่นที่รองรับ ความรู้สึกของฉันคือใน Linux มันมีทางออกเดียวที่พกพาได้



0

ทำงานร่วมกับการเริ่มต้นจาก C ++ 11 โดยใช้ระบบไฟล์ทดลองและ C ++ 14-C ++ 17 รวมถึงการใช้ระบบไฟล์อย่างเป็นทางการ

application.h:

#pragma once

//
// https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros
//
#ifdef __cpp_lib_filesystem
#include <filesystem>
#else
#include <experimental/filesystem>

namespace std {
    namespace filesystem = experimental::filesystem;
}
#endif

std::filesystem::path getexepath();

application.cpp:

#include "application.h"
#ifdef _WIN32
#include <windows.h>    //GetModuleFileNameW
#else
#include <limits.h>
#include <unistd.h>     //readlink
#endif

std::filesystem::path getexepath()
{
#ifdef _WIN32
    wchar_t path[MAX_PATH] = { 0 };
    GetModuleFileNameW(NULL, path, MAX_PATH);
    return path;
#else
    char result[PATH_MAX];
    ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
    return std::string(result, (count > 0) ? count : 0);
#endif
}

คำตอบที่ดี แต่พฤติกรรมมันจะไม่ได้กำหนดที่จะเพิ่มการประกาศหรือคำจำกัดความถึง stdnamespace เพื่อหลีกเลี่ยงปัญหานี้คุณสามารถเพิ่มทั้งเนมสเปซstd::filesystemและเนมสเปซstd::experimental::filesystemที่สามที่คุณเลือกหรือเพียงแค่ใช้using std::filesystem::pathถ้าคุณไม่รังเกียจที่จะเพิ่มการประกาศของpathเนมสเปซส่วนกลาง
Cássio Renan

ฉันเดาว่าหลังจากระบบไฟล์ C ++ 14 รุ่นทดลองใช้ไม่ได้ใช้อีกต่อไปแล้วคุณสามารถลืมมันได้หรือไม่ (ไปที่ #if สาขาแรก)
TarmoPikaro
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.