Cách lấy kích thước tệp tính bằng byte với C ++ 17


97

Có những cạm bẫy cho các hệ điều hành cụ thể mà tôi nên biết không?

Có rất nhiều bản sao ( 1 , 2 , 3 , 4 , 5 ) của câu hỏi này nhưng chúng đã được trả lời từ nhiều thập kỷ trước. Ngày nay, câu trả lời được bình chọn rất cao trong nhiều câu hỏi này là sai.

Các phương thức từ khác (QA cũ) trên .sx

  • stat.h (wrapper sprintstatf ), sử dụng syscall

  • Tellg () , trả về cho mỗi định nghĩa một vị trí nhưng không nhất thiết là byte . Loại trả lại không phải int.



5
@LF: Chà, câu hỏi đầu tiên đã bị đóng lại là bản sao của câu hỏi thứ hai, điều này giải thích tại sao câu trả lời được chấp nhận trong câu hỏi đầu tiên là sai . Người thứ ba đang hỏi về những tellgvấn đề tương tự . Cái duy nhất đáng bận tâm là cái thứ tư, và cái đó không hay lắm, vì nó nói quá nhiều về ofstreamcả câu hỏi lẫn câu trả lời. Cái này diễn đạt ý định tốt hơn nhiều so với những cái khác (ngoại trừ cái đầu tiên, được đóng một cách kỳ lạ).
Nicol Bolas

6
Vui lòng ngừng thêm thông tin không liên quan vào câu hỏi của bạn và tiêu đề câu hỏi. Năm không liên quan; các công nghệ có liên quan.
elixenide

2
Có gì sai với stat(2)dù sao? Nó đã già quá hay sao?
Lorinczy Zsigmond

1
@LorinczyZsigmond Có gì sai vớistat(2) Nó không phải là một phần của tiêu chuẩn ngôn ngữ.
Andrew Henle

Câu trả lời:


122

<filesystem>(được thêm vào trong C ++ 17) làm cho điều này rất đơn giản .

#include <cstdint>
#include <filesystem>

// ...

std::uintmax_t size = std::filesystem::file_size("c:\\foo\\bar.txt");

Như đã lưu ý trong phần nhận xét, nếu bạn định sử dụng hàm này để quyết định xem có bao nhiêu byte để đọc từ tệp, hãy nhớ rằng ...

... trừ khi tệp do bạn độc quyền mở, kích thước của tệp có thể được thay đổi giữa thời gian bạn yêu cầu và thời gian bạn cố gắng đọc dữ liệu từ tệp.
- Nicol Bolas


11
Little offtopic: liệu có một thế giới std::uintmax_tnào có thể lưu giữ những giá trị lớn hơn std::size_tkhông? Nếu không, tại sao không sử dụng std::size_t, cái nào được cho là dễ nhận biết hơn? +1 cho câu trả lời, btw
Fureeish

13
@Fureeish tôi đã sử dụng chỉ vì đó là kiểu file_sizetrả về. Trông tôi cũng hơi kỳ lạ.
HolyBlackCat

39
@Fureeish std::size_tchỉ được yêu cầu để giữ kích thước tối đa của các đối tượng bộ nhớ. Các tập tin có thể lớn hơn đáng kể,
Richard C Viết

26
@Fureeish Chà, trên Windows 32 bit (và tôi cho rằng trên hầu hết các nền tảng size_t32 bit hiện đại) là 32 bit và uintmax_tlà 64 bit.
HolyBlackCat

16
@HolyBlackCat: Sẽ rất tốt nếu bạn nói điều gì đó về thực tế là hệ thống tệp là toàn cầu, và do đó, trừ khi tệp được bạn độc quyền mở, kích thước của tệp có thể được thay đổi giữa thời gian bạn yêu cầu và thời gian bạn cố gắng đọc dữ liệu từ nó.
Nicol Bolas

28

C ++ 17 mang lại sự std::filesystemhợp lý hóa rất nhiều tác vụ trên các tệp và thư mục. Bạn không chỉ có thể nhanh chóng nhận được kích thước tệp, các thuộc tính của nó mà còn có thể tạo thư mục mới, lặp qua các tệp, làm việc với các đối tượng đường dẫn.

Thư viện mới cung cấp cho chúng ta hai hàm mà chúng ta có thể sử dụng:

std::uintmax_t std::filesystem::file_size( const std::filesystem::path& p );

std::uintmax_t std::filesystem::directory_entry::file_size() const;

Hàm đầu tiên là một hàm miễn phí trong std::filesystem, hàm thứ hai là một phương thức trong directory_entry.

Mỗi phương thức cũng có một quá tải, vì nó có thể ném ra một ngoại lệ hoặc trả về một mã lỗi (thông qua một tham số đầu ra). Dưới đây là mã chi tiết giải thích tất cả các trường hợp có thể xảy ra.

#include <chrono>
#include <filesystem>  
#include <iostream>

namespace fs = std::filesystem;

int main(int argc, char* argv[])
{
    try
    {
        const auto fsize = fs::file_size("a.out");
        std::cout << fsize << '\n';
    }
    catch (const fs::filesystem_error& err)
    {
        std::cerr << "filesystem error! " << err.what() << '\n';
        if (!err.path1().empty())
            std::cerr << "path1: " << err.path1().string() << '\n';
        if (!err.path2().empty())
            std::cerr << "path2: " << err.path2().string() << '\n';
    }
    catch (const std::exception& ex)
    {
        std::cerr << "general exception: " << ex.what() << '\n';
    }

    // using error_code
    std::error_code ec{};
    auto size = std::filesystem::file_size("a.out", ec);
    if (ec == std::error_code{})
        std::cout << "size: " << size << '\n';
    else
        std::cout << "error when accessing test file, size is: " 
              << size << " message: " << ec.message() << '\n';
}

2
Chính xác thì "cái này" là gì? Bạn có thể giải thích tất cả mã này được sử dụng để làm gì, đặc biệt là khi câu trả lời được chấp nhận sử dụng ít mã hơn nhiều?
Nico Haase
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.