Làm thế nào để xây dựng một chuỗi đường dẫn đầy đủ (một cách an toàn) từ các chuỗi riêng biệt?


89

C ++ có bất kỳ tương đương với chức năng của python os.path.joinkhông? Về cơ bản, tôi đang tìm kiếm thứ gì đó kết hợp hai (hoặc nhiều) phần của đường dẫn tệp để bạn không phải lo lắng về việc đảm bảo hai phần khớp với nhau một cách hoàn hảo. Nếu nó ở Qt, điều đó cũng rất tuyệt.

Về cơ bản, tôi đã dành một giờ để gỡ lỗi một số mã và ít nhất một phần của nó là do root + filenamephải như vậy root/ + filename, và tôi đang tìm cách tránh điều đó trong tương lai.


Có thể họ hàng xa: stackoverflow.com/questions/5772992/... (đặc biệt là liên quan đến rằng câu hỏi là tăng của complete)
Lightness Races ở Orbit

Câu trả lời:


44

Kiểm tra QDir cho điều đó:

QString path = QDir(dirPath).filePath(fileName);

3
Lưu ý rằng Qt là GPL. Có thể là một công cụ thỏa thuận cho nhiều mục đích sử dụng.
gỉ sắt

2
@RustyX, chính xác là LGPL.
Pa_

97

Chỉ là một phần của thư viện Boost.Filesystem . Đây là một ví dụ:

#include <iostream>
#include <boost/filesystem.hpp>

namespace fs = boost::filesystem;

int main ()
{
    fs::path dir ("/tmp");
    fs::path file ("foo.txt");
    fs::path full_path = dir / file;
    std::cout << full_path << std::endl;
    return 0;
}

Đây là một ví dụ về biên dịch và chạy (nền tảng cụ thể):

$ g++ ./test.cpp -o test -lboost_filesystem -lboost_system
$ ./test 
/tmp/foo.txt

1
Điều này cũng nằm trong TR2, có khả năng sẽ bắt đầu giao hàng với các trình biên dịch vào năm tới.
ildjarn

1
@Vlad: Vâng, nó không dễ phát hiện, nhưng tôi ghét việc nhấp vào các liên kết Boost doc và muộn màng nhận ra rằng tôi đang xem một phiên bản cũ, vì vậy tôi chỉnh sửa các liên kết dành riêng cho phiên bản của mọi người khi tôi bắt gặp chúng. :-P
ildjarn

1
@ildjarn: Hiện tại có vẻ đang hoạt động tốt ... nhưng hãy đợi cho đến khi họ thay đổi điều gì đó về trang web hoặc tài liệu cho thư viện đã cho. Còn tệ hơn là rời khỏi liên kết phiên bản cụ thể từ đó trở đi.
Fred Nurk

1
@Fred: Rõ ràng là nếu chức năng hoặc câu hỏi xảy ra với phiên bản cụ thể, tôi không thay đổi URL. Trong trường hợp này, nó không phải, vì vậy tôi đã làm.
ildjarn

1
@ildjarn: Làm thế nào để bạn dự đoán những gì một thư viện nhất định sẽ thay đổi trong tương lai để bạn có thể biết liệu tất cả các câu trả lời bạn chỉnh sửa có phù hợp với tất cả các phiên bản trong tương lai hay không?
Fred Nurk

24

Tương tự như câu trả lời của @ user405725 (nhưng không sử dụng boost) và được @ildjarn đề cập trong một nhận xét, chức năng này khả dụng như một phần của hệ thống tệp std :: . Mã sau đây biên dịch bằng Homebrew GCC 9.2.0_1 và sử dụng cờ --std=c++17:

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

int main() 
{
    fs::path dir ("/tmp");
    fs::path file ("foo.txt");
    fs::path full_path = dir / file;
    std::cout << full_path << std::endl;
    return 0;
}

4
Kể từ C ++ 17, điều này đã được hợp nhất vào tiêu đề <filesystem> (không thử nghiệm). Xem en.cppreference.com/w/cpp/filesystem .
Eli_B

9

Ít nhất trong Unix / Linux, luôn an toàn khi tham gia các phần của đường dẫn bằng /, ngay cả khi một số phần của đường dẫn đã kết thúc /, tức root/pathlà tương đương với root//path.

Trong trường hợp này, tất cả những gì bạn thực sự cần là tham gia mọi thứ /. Điều đó nói rằng, tôi đồng ý với các câu trả lời khác rằng đó boost::filesystemlà một lựa chọn tốt nếu nó có sẵn cho bạn vì nó hỗ trợ nhiều nền tảng.


2
QT là bất khả tri đối với dấu phân cách đường dẫn. Nếu bạn in đường dẫn tuyệt đối của tệp trên Windows, đầu ra là "C: /Users/Name/MyFile.txt" với dấu phân tách / (unix). boost :: filesystem là tuyệt vời, nhưng theo tôi, nếu dự án dựa trên Qt thì không cần thêm phụ thuộc vào thư viện boost.
LoSciamano

7

Nếu bạn muốn làm điều này với Qt, bạn có thể sử dụng hàm QFileInfotạo:

QFileInfo fi( QDir("/tmp"), "file" );
QString path = fi.absoluteFilePath();

4

Với C ++ 11 và Qt, bạn có thể làm điều này:

QString join(const QString& v) {
    return v;
}

template<typename... Args>
QString join(const QString& first, Args... args) {
    return QDir(first).filePath(join(args...));
}

Sử dụng:

QString path = join("/tmp", "dir", "file"); // /tmp/dir/file

3

Trong Qt, chỉ sử dụng /trong mã khi sử dụng API Qt ( QFile, QFileInfo). Nó sẽ làm điều đúng đắn trên tất cả các nền tảng. Nếu bạn phải chuyển một đường dẫn đến một hàm không phải Qt hoặc muốn định dạng nó để hiển thị nó cho người dùng, hãy sử dụng QDir:toNativeSeparators()ví dụ:

QDir::toNativeSeparators( path );

Nó sẽ thay thế /bằng bản gốc tương đương (tức là \trên Windows). Hướng khác được thực hiện thông qua QDir::fromNativeSeparators().

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.