Cara mendapatkan ukuran file dalam byte dengan C ++ 17

97

Apakah ada kendala untuk sistem operasi tertentu, yang harus saya ketahui?

Ada banyak duplikat ( 1 , 2 , 3 , 4 , 5 ) dari pertanyaan ini tetapi sudah dijawab beberapa dekade yang lalu. Jawaban yang sangat dipilih dalam banyak pertanyaan ini salah hari ini.

Metode dari lain (QA lama) di .sx

  • stat.h (wrapper sprintstatf ), menggunakan syscall

  • tellg () , mengembalikan per definisi posisi tetapi tidak harus byte . Jenis pengembalian tidak int.

Jonas Stein
sumber
4
Starter untuk 10: en.cppreference.com/w/cpp/header/filesystem
Richard Critten
5
@LF: Ya, pertanyaan pertama telah ditutup sebagai duplikat dari pertanyaan kedua, yang menjelaskan mengapa jawaban yang diterima di pertanyaan pertama salah . Yang ketiga menanyakan tentang tellgmasalah yang serupa . Satu-satunya yang perlu diganggu adalah yang keempat, dan yang satu itu tidak hebat, karena terlalu banyak membicarakan ofstream, baik dalam pertanyaan maupun jawabannya. Yang ini jauh lebih baik dalam mengungkapkan maksud daripada yang lain (kecuali yang pertama, yang anehnya ditutup).
Nicol Bolas
6
Harap berhenti menambahkan informasi yang tidak relevan ke pertanyaan Anda dan judul pertanyaan. Tahun tidak relevan; teknologinya relevan.
elixenide
2
Ada apa sih stat(2)? Apakah sudah terlalu tua atau apa?
Lorinczy Zsigmond
1
@LorinczyZsigmond Apa yang salah denganstat(2) Ini bukan bagian dari standar bahasa.
Andrew Henle

Jawaban:

123

<filesystem>(ditambahkan di C ++ 17) membuat ini sangat mudah .

#include <cstdint>
#include <filesystem>

// ...

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

Seperti disebutkan dalam komentar, jika Anda berencana menggunakan fungsi ini untuk memutuskan berapa banyak byte yang akan dibaca dari file, perlu diingat bahwa ...

... kecuali file dibuka secara eksklusif oleh Anda, ukurannya dapat diubah antara waktu Anda memintanya dan waktu Anda mencoba membaca data darinya.
- Nicol Bolas

HolyBlackCat
sumber
11
Sedikit offtopic: adakah dunia di mana std::uintmax_takan dapat menyimpan nilai-nilai lebih dari std::size_t? Jika tidak, mengapa tidak digunakan std::size_t, yang bisa dibilang lebih dikenali? +1 pada jawabannya, btw
Fureeish
13
@Fureeish saya gunakan hanya karena itulah tipe file_sizepengembalian. Terlihat agak aneh juga bagiku.
HolyBlackCat
39
@Fureeish std::size_thanya diperlukan untuk menampung ukuran maksimal dalam objek memori. File bisa jauh lebih besar,
Richard Critten
27
@Fureeish Nah, pada Windows 32-bit (dan saya berasumsi pada sebagian besar platform 32-bit modern) size_tadalah 32 bit, dan uintmax_t64 bit.
HolyBlackCat
16
@HolyBlackCat: Sebaiknya katakan sesuatu tentang fakta bahwa sistem file bersifat global, dan dengan demikian, kecuali jika file dibuka secara eksklusif oleh Anda, ukurannya dapat diubah antara saat Anda memintanya dan waktu Anda mencoba membaca data dari itu.
Nicol Bolas
28

C ++ 17 menghadirkan std::filesystemyang menyederhanakan banyak tugas pada file dan direktori. Tidak hanya Anda dapat dengan cepat mendapatkan ukuran file, atributnya, tetapi juga membuat direktori baru, melakukan iterasi melalui file, bekerja dengan objek jalur.

Perpustakaan baru memberi kita dua fungsi yang bisa kita gunakan:

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

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

Fungsi pertama adalah fungsi bebas di std::filesystem, yang kedua adalah metode masuk directory_entry.

Setiap metode juga memiliki kelebihan beban, karena dapat memunculkan pengecualian atau mengembalikan kode kesalahan (melalui parameter keluaran). Di bawah ini adalah kode detail yang menjelaskan semua kemungkinan kasus.

#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';
}
GOVIND DIXIT
sumber
2
Apa sebenarnya "ini"? Bisakah Anda menjelaskan untuk apa semua kode ini digunakan, terutama ketika jawaban yang diterima menggunakan lebih sedikit kode?
Nico Haase