Using C++ filestreams (fstream), how can you determine the size of a file?
You can open the file using the ios::ate
flag (and ios::binary
flag), so the tellg()
function will directly give you directly the file size:
ifstream file( "example.txt", ios::binary | ios::ate);
return file.tellg();
How can I determine the current size of the file opened by std::ofstream?
fstreams can be both input and output streams. tellg()
will return the input position and tellp()
will tell you of the output position. tellp()
will after appending to a file tell you its size.
Consider initializing your Logger like this (edit: added example for output stream operator):
#include <iostream>
#include <fstream>
class Logger {
std::string m_filename;
std::ofstream m_os;
std::ofstream::pos_type m_curr_size;
std::ofstream::pos_type m_max_size;
public:
Logger(const std::string& logfile, std::ofstream::pos_type max_size) :
m_filename(logfile),
m_os(m_filename, std::ios::app),
m_curr_size(m_os.tellp()),
m_max_size(max_size)
{}
template<typename T>
friend Logger& operator<<(Logger&, const T&);
};
template<typename T>
Logger& operator<<(Logger& log, const T& msg) {
log.m_curr_size = (log.m_os << msg << std::flush).tellp();
if(log.m_curr_size>log.m_max_size) {
log.m_os.close();
//rename & compress
log.m_os = std::ofstream(log.m_filename, std::ios::app);
log.m_curr_size = log.m_os.tellp();
}
return log;
}
int main()
{
Logger test("log", 4LL*1024*1024*1024*1024);
test << "hello " << 10 << "\n";
return 0;
}
If you use C++17 or have an experimental version of <filesystem>
available, you could also use that to get the absolute file size, like this:
#include <iostream>
#include <fstream>
#include <filesystem>
namespace fs = std::filesystem;
class Logger {
fs::directory_entry m_logfile;
std::ofstream m_os;
std::uintmax_t m_max_size;
void rotate_if_needed() {
if(max_size_reached()) {
m_os.close();
//rename & compress
m_os = std::ofstream(m_logfile.path(), std::ios::app);
}
}
public:
Logger(const std::string& logfile, std::uintmax_t max_size) :
m_logfile(logfile),
m_os(m_logfile.path(), std::ios::app),
m_max_size(max_size)
{
// make sure the path is absolute in case the process
// have changed current directory when we need to rotate the log
if(m_logfile.path().is_relative())
m_logfile = fs::directory_entry(fs::absolute(m_logfile.path()));
}
std::uintmax_t size() const { return m_logfile.file_size(); }
bool max_size_reached() const { return size()>m_max_size; }
template<typename T>
friend Logger& operator<<(Logger&, const T&);
};
template<typename T>
Logger& operator<<(Logger& log, const T& msg) {
log.m_os << msg << std::flush;
log.rotate_if_needed();
return log;
}
int main()
{
Logger test("log", 4LL*1024*1024*1024*1024);
std::cout << test.size() << "\n";
test << "hello " << 10 << "\n";
std::cout << test.size() << "\n";
test << "some more " << 3.14159 << "\n";
std::cout << test.size() << "\n";
return 0;
}
How can I get a file's size in C++?
#include <fstream>
std::ifstream::pos_type filesize(const char* filename)
{
std::ifstream in(filename, std::ifstream::ate | std::ifstream::binary);
return in.tellg();
}
See http://www.cplusplus.com/doc/tutorial/files/ for more information on files in C++.
edit: this answer is not correct since tellg() does not necessarily return the right value. See http://stackoverflow.com/a/22986486/1835769
How does a program determine the size of a file without reading it whole?
The size of the file is embedded in the file metadata in the file system. Different file systems have different ways of storing this information.
Edit Obviously, this is an incomplete answer. When someone will provide an answer where he'll exemplify on a common filesystem like ex3 or ntfs or fat exactly how the file size it's known and stored, i'll delete this answer.
Get file size with std::ios::ate?
It should work just fine. The C++ standard says about std::ios::ate
ate
- open and seek to end immediately after opening
There's no reason it would fail when a manual open-then-seek would succeed. And tellg
is the same in either case.
filestream to vector, filesize wrong
std::istream_iterator<unsigned char>
is a formatted input iterator that skips whitespace, that is why your vector is short.
Use std::istreambuf_iterator<char>
instead, it reads data verbatim.
Note that the meaning of the template argument is quite different between these two iterators. In the latter case it is the type of symbols decoded by std::char_traits<>
(e.g. you may want to decode a utf-8 encoded file as sequence of wchar_t
). std::istreambuf_iterator<char>
does identity decoding. C++ streams have been using char
type for representing binary data (see std::ostream::write
, for example).
Related Topics
Store Functions with Different Signatures in a Map
Correct Use of Std::Cout.Precision() - Not Printing Trailing Zeros
Why Doesn't Sfinae (Enable_If) Work for Member Functions of a Class Template
Is Adding to a "Char *" Pointer Ub, When It Doesn't Actually Point to a Char Array
Problems with Std::Stoi, Not Working on Mingw Gcc 4.7.2
What Is the Proper Opengl Initialisation on Intel Hd 3000
C++ Standard Library and Boehm Garbage Collector
Math-Like Chaining of the Comparison Operator - as In, "If ( (5<J<=1) )"
How Do Exceptions Work (Behind the Scenes) in C++
How to Build an Import Library (.Lib) and a Dll in Visual C++
Algorithm for Finding the Smallest Power of Two That's Greater or Equal to a Given Value
Remove C and C++ Comments Using Python
How to Convert Std::Chrono::Time_Point to Calendar Datetime String with Fractional Seconds