Apakah ada metode platform-agnostik dan filesystem-agnostik untuk mendapatkan path lengkap direktori dari tempat program berjalan menggunakan C / C ++? Jangan bingung dengan direktori kerja saat ini. (Tolong jangan menyarankan perpustakaan kecuali perpustakaan yang standar seperti clib atau STL.)
(Jika tidak ada metode platform / filesystem-agnostik, saran yang bekerja di Windows dan Linux untuk sistem file tertentu juga diterima.)
c++
c
working-directory
Ashwin Nanjappa
sumber
sumber
argv[0]
, tekniknya akan sangat bergantung pada OS.#include <windows.h>
, Windows secara otomatis menempatkan achar*
ke jalur yang dapat dieksekusi di_pgmptr
. Anda tidak perlu memanggil fungsi tambahan atau menganggap sampah jika Anda hanya bekerja pada Windows._pgmptr
. Dokumentasi MSDN menyatakan bahwa variabel_pgmptr
dan_wpgmptr
sudah usang, dan Anda harus menggunakan fungsi_get_pgmptr(char**)
atau_get_wpgmptr(wchar_t**)
sebagai gantinya. MSDNJawaban:
Berikut kode untuk mendapatkan path lengkap ke aplikasi yang menjalankan:
Windows:
Linux:
sumber
/proc
bagian saya mati sedikit. Seluruh dunia bukan Linux, dan bahkan pada satu platform itu/proc
harus dianggap dapat berubah dari versi ke versi, lengkungan ke lengkungan, dll.char pBuf[256]; size_t len = sizeof(pBuf);
untuk membiarkan solusi lebih jelas.Jika Anda mengambil direktori saat ini ketika program Anda pertama kali dimulai, maka Anda secara efektif memiliki direktori tempat program Anda dimulai. Simpan nilai dalam variabel dan lihat nanti di program Anda. Ini berbeda dari direktori yang menyimpan file program yang dapat dieksekusi saat ini . Itu belum tentu direktori yang sama; jika seseorang menjalankan program dari prompt perintah, maka program sedang dijalankan dari direktori yang berfungsi prompt perintah saat ini meskipun file program tinggal di tempat lain.
getcwd adalah fungsi POSIX dan didukung di luar kotak oleh semua platform yang sesuai dengan POSIX. Anda tidak perlu melakukan sesuatu yang istimewa (selain menyertakan tajuk kanan unistd.h di Unix dan direct.h di windows).
Karena Anda membuat program C, program itu akan ditautkan dengan pustaka c run time default yang ditautkan dengan SEMUA proses dalam sistem (pengecualian yang dibuat khusus dihindari) dan itu akan menyertakan fungsi ini secara default. CRT tidak pernah dianggap sebagai perpustakaan eksternal karena menyediakan antarmuka standar yang sesuai dengan OS.
Pada fungsi getcwd windows telah ditinggalkan demi _getcwd. Saya pikir Anda bisa menggunakannya dengan cara ini.
sumber
Ini dari forum cplusplus
Di windows:
Di Linux:
Di HP-UX:
sumber
error: cannot convert 'char*' to 'LPWCH {aka wchar_t*}' for argument '2' to 'DWORD GetModuleFileNameW(HMODULE, LPWCH, DWORD)'
saat kompilasi dengan MinGW.Jika Anda menginginkan cara standar tanpa pustaka: Tidak. Seluruh konsep direktori tidak termasuk dalam standar.
Jika Anda setuju bahwa beberapa ketergantungan (portabel) pada lib yang hampir standar tidak apa-apa: Gunakan pustaka sistem file Boost dan minta initial_path () .
IMHO itu sedekat yang Anda bisa dapatkan, dengan karma yang baik (Boost adalah sekumpulan perpustakaan berkualitas tinggi)
sumber
Filesystem TS sekarang menjadi standar (dan didukung oleh gcc 5.3+ dan clang 3.9+), sehingga Anda dapat menggunakan
current_path()
fungsi darinya:Dalam gcc (5.3+) untuk memasukkan Filesystem, Anda perlu menggunakan:
dan tautkan kode Anda dengan
-lstdc++fs
bendera.Jika Anda ingin menggunakan Filesystem dengan Microsoft Visual Studio, baca ini .
sumber
1-2) Returns the absolute path of the current working directory, obtained as if by POSIX getcwd. (2) returns path() if error occurs.
direferensikan , Diturunkan, karena OP secara khusus bertanya tentang jalur saat ini yang dapat dieksekusi daripada direktori kerja saat ini.Saya tahu sudah sangat terlambat untuk memberikan jawaban yang satu ini tetapi saya menemukan bahwa tidak ada jawaban yang berguna bagi saya sebagai solusi saya sendiri. Cara yang sangat sederhana untuk mendapatkan path dari CWD Anda ke folder bin Anda adalah seperti ini:
Anda sekarang dapat menggunakan ini sebagai basis untuk jalur relatif Anda. Jadi misalnya saya punya struktur direktori ini:
dan saya ingin mengkompilasi kode sumber saya ke bin dan menulis log untuk menguji saya bisa menambahkan baris ini ke kode saya.
Saya telah mencoba pendekatan ini di Linux menggunakan path lengkap, alias dll dan berfungsi dengan baik.
CATATAN:
Jika Anda berada di windows Anda harus menggunakan '\' sebagai pemisah file bukan '/'. Anda harus menghindari ini juga misalnya:
Saya pikir ini harus bekerja tetapi belum diuji, jadi komentar akan dihargai jika berhasil atau diperbaiki jika tidak.
sumber
argv[0]
adalah ide yang sangat bagus, tetapi sayangnya apa yang saya dapatkan di Linux adalah "./my_executable_name" atau "./make/my_executable_name". Pada dasarnya apa yang saya dapatkan tergantung sepenuhnya pada bagaimana saya meluncurkannyaTidak, tidak ada cara standar. Saya percaya bahwa standar C / C ++ bahkan tidak mempertimbangkan keberadaan direktori (atau organisasi sistem file lainnya).
Pada Windows, GetModuleFileName () akan mengembalikan path lengkap ke file yang dapat dieksekusi dari proses saat ini ketika parameter hModule diatur ke NULL . Saya tidak dapat membantu dengan Linux.
Anda juga harus mengklarifikasi apakah Anda ingin direktori saat ini atau direktori yang gambar program / executable berada. Saat ini, pertanyaan Anda sedikit ambigu dalam hal ini.sumber
Pada Windows cara paling sederhana adalah dengan menggunakan
_get_pgmptr
fungsistdlib.h
untuk mendapatkan pointer ke string yang mewakili jalur absolut ke executable, termasuk nama executable.sumber
Mungkin merangkai direktori kerja saat ini dengan argv [0]? Saya tidak yakin apakah itu akan bekerja di Windows tetapi bekerja di linux.
Sebagai contoh:
Saat dijalankan, ini menghasilkan:
sumber
Untuk Win32 GetCurrentDirectory harus melakukan trik.
sumber
Anda tidak dapat menggunakan argv [0] untuk tujuan itu, biasanya itu berisi path lengkap ke executable, tetapi tidak perlu - proses dapat dibuat dengan nilai arbitrer di lapangan.
Ingat juga, direktori saat ini dan direktori dengan executable adalah dua hal yang berbeda, jadi getcwd () tidak akan membantu Anda juga.
Pada Windows gunakan file GetModuleFileName (), di Linux baca / dev / proc / procID / ...
sumber
Hanya untuk tumpukan terlambat di sini, ...
tidak ada solusi standar, karena bahasa-bahasa tersebut agnostik dari sistem file yang mendasarinya, sehingga seperti yang dikatakan orang lain, konsep sistem file berbasis direktori berada di luar lingkup bahasa c / c ++.
di atas itu, Anda tidak ingin direktori kerja saat ini, tetapi direktori program sedang berjalan, yang harus memperhitungkan bagaimana program sampai di tempat itu - yaitu apakah itu menelurkan sebagai proses baru melalui garpu, dll. Untuk mendapatkan direktori, sebuah program sedang berjalan, seperti yang ditunjukkan oleh solusi, mengharuskan Anda mendapatkan informasi itu dari struktur kontrol proses sistem operasi yang bersangkutan, yang merupakan satu-satunya otoritas pada pertanyaan ini. Jadi, menurut definisi, ini merupakan solusi spesifik OS.
sumber
Untuk sistem Windows di konsol Anda dapat menggunakan
dir
perintah system ( ). Dan konsol memberi Anda informasi tentang direktori dan lain-lain. Baca tentangdir
perintah dicmd
. Tetapi untuk sistem mirip Unix, saya tidak tahu ... Jika perintah ini dijalankan, baca perintah bash.ls
tidak menampilkan direktori ...Contoh:
sumber
sumber
Pada platform POSIX, Anda dapat menggunakan getcwd () .
Di Windows, Anda dapat menggunakan _getcwd () , seperti penggunaan getcwd () telah ditinggalkan.
Untuk pustaka standar, jika Boost cukup standar untuk Anda, saya akan menyarankan Boost :: filesystem, tetapi mereka tampaknya telah menghapus normalisasi jalur dari proposal. Anda mungkin harus menunggu sampai TR2 tersedia untuk solusi standar sepenuhnya.
sumber
Untuk jalur relatif, inilah yang saya lakukan. Saya menyadari usia pertanyaan ini, saya hanya ingin berkontribusi jawaban yang lebih sederhana yang bekerja di sebagian besar kasus:
Katakanlah Anda memiliki jalur seperti ini:
Untuk beberapa alasan, executable buatan Linux yang dibuat di eclipse berfungsi baik dengan ini. Namun, windows menjadi sangat bingung jika diberikan jalur seperti ini untuk bekerja dengannya!
Seperti yang dinyatakan di atas ada beberapa cara untuk mendapatkan jalur saat ini ke executable, tetapi cara termudah yang saya temukan bekerja pesona di sebagian besar kasus adalah menambahkan ini ke DEPAN jalur Anda:
Hanya menambahkan "./" akan membuat Anda diurutkan! :) Kemudian Anda dapat mulai memuat dari direktori apa pun yang Anda inginkan, asalkan dengan executable itu sendiri.
EDIT: Ini tidak akan berfungsi jika Anda mencoba meluncurkan executable from code :: blocks jika itu lingkungan pengembangan yang digunakan, karena beberapa alasan, code :: blocks tidak memuat barang dengan benar ...: D
EDIT2: Beberapa hal baru yang saya temukan adalah bahwa jika Anda menentukan jalur statis seperti ini dalam kode Anda (Mengasumsikan Example.data adalah sesuatu yang Anda perlu memuat):
Jika Anda kemudian meluncurkan aplikasi Anda dari direktori aktual (atau di Windows, Anda membuat jalan pintas, dan mengatur direktori kerja ke direktori aplikasi Anda) maka itu akan berfungsi seperti itu. Ingatlah ini ketika men-debug masalah yang terkait dengan sumber daya / jalur file yang hilang. (Terutama di IDE yang mengatur dir yang salah saat meluncurkan build exe dari IDE)
sumber
Solusi perpustakaan (meskipun saya tahu ini tidak diminta). Jika Anda menggunakan Qt:
QCoreApplication::applicationDirPath()
sumber
Hanya dua sen saya, tetapi tidakkah kode berikut ini berfungsi baik di C ++ 17?
Tampaknya bekerja untuk saya di Linux setidaknya.
Berdasarkan ide sebelumnya, saya sekarang memiliki:
Dengan implementasi:
Dan trik inisialisasi dalam
main()
:Terima kasih @Sam Redway untuk ide [0] argv. Dan tentu saja, saya mengerti bahwa C ++ 17 tidak ada selama bertahun-tahun ketika OP mengajukan pertanyaan.
sumber
Tingkatkan Filesystem
initial_path()
berperilaku seperti POSIXgetcwd()
, dan tidak juga melakukan apa yang Anda inginkan dengan sendirinya, tetapi menambahkannyaargv[0]
ke salah satu dari mereka harus melakukannya.Anda mungkin mencatat bahwa hasilnya tidak selalu cantik - Anda mungkin mendapatkan hal-hal seperti
/foo/bar/../../baz/a.out
atau/foo/bar//baz/a.out
, tetapi saya percaya bahwa itu selalu menghasilkan jalur yang valid yang menamai executable (perhatikan bahwa garis miring berturut-turut di jalan diciutkan menjadi satu).Saya sebelumnya menulis solusi menggunakan
envp
(argumen ketigamain()
yang bekerja di Linux tetapi tampaknya tidak bisa diterapkan pada Windows, jadi saya pada dasarnya merekomendasikan solusi yang sama seperti yang dilakukan orang lain sebelumnya, tetapi dengan penjelasan tambahan mengapa itu sebenarnya benar bahkan jika hasilnya tidak cantik.sumber
Sebagai Minok disebutkan , tidak ada fungsi yang ditentukan dalam standar C atau standar C ++ ini. Ini dianggap murni fitur OS-spesifik dan ditentukan dalam standar POSIX, misalnya.
Thorsten79 telah memberikan saran yang baik, itu adalah perpustakaan Boost.Filesystem. Namun, mungkin tidak nyaman jika Anda tidak ingin memiliki dependensi waktu tautan dalam bentuk biner untuk program Anda.
Alternatif yang baik yang saya sarankan adalah koleksi 100% header-only STLSoft C ++ Libraries Matthew Wilson (penulis buku yang harus dibaca tentang C ++). Ada fasad portabel PlatformSTL memberikan akses ke API khusus sistem: WinSTL untuk Windows dan UnixSTL di Unix, jadi ini adalah solusi portabel. Semua elemen khusus sistem ditentukan dengan penggunaan sifat dan kebijakan, sehingga merupakan kerangka yang dapat diperluas. Ada perpustakaan filesystem yang disediakan, tentu saja.
sumber
Perintah linux bash yang progname akan melaporkan path ke program.
Bahkan jika seseorang dapat mengeluarkan perintah yang mana dari dalam program Anda dan mengarahkan output ke file tmp dan program selanjutnya membaca file tmp itu, ia tidak akan memberi tahu Anda apakah program itu yang menjalankan. Ini hanya memberi tahu Anda di mana program yang memiliki nama itu berada.
Apa yang diperlukan adalah untuk mendapatkan nomor id proses Anda, dan untuk mem-parsing path ke nama
Dalam program saya, saya ingin tahu apakah program itu dijalankan dari direktori bin pengguna atau dari yang lain di path atau dari / usr / bin. / usr / bin akan berisi versi yang didukung. Perasaan saya adalah bahwa di Linux ada satu solusi yang portabel.
sumber
Gunakan
realpath()
distdlib.h
seperti ini:sumber
Bekerja dengan mulai dari C ++ 11, menggunakan filesystem eksperimental, dan C ++ 14-C ++ 17 juga menggunakan filesystem resmi.
application.h:
application.cpp:
sumber
std
. Untuk menghindari ini, Anda bisa menambahkan ruang namastd::filesystem
danstd::experimental::filesystem
ruang nama ketiga pilihan Anda, atau gunakan sajausing std::filesystem::path
, jika Anda tidak keberatan menambahkan deklarasipath
ke ruang nama global.