Handling file sizes correctly

M

Matthias Kaeppler

Hello,

in my application, I want to print file sizes in a human readable
format. However, I remember a thread here which dealt with a similar
issue, and people said it'd be a bad idea to write numbers like 1024 and
so on explicitly. Unfortunately I can't remember the reason.

Can you elaborate on that?

Thanks.
 
S

Siemel Naran

in my application, I want to print file sizes in a human readable
format. However, I remember a thread here which dealt with a similar
issue, and people said it'd be a bad idea to write numbers like 1024 and
so on explicitly. Unfortunately I can't remember the reason.

Can you elaborate on that?

Hmmm. To write numbers in human readable format seems to be always safe. I
think by writing directly they might have meant writing the bit
representation to the file. Problem with this method is that it is not
portable, as different platforms has different sizeof for the same integer
type, and the endian-ness may be different too, plus there will be other
differences in floating point representation.
 
M

Matthias Kaeppler

Matthias said:
Hello,

in my application, I want to print file sizes in a human readable
format. However, I remember a thread here which dealt with a similar
issue, and people said it'd be a bad idea to write numbers like 1024 and
so on explicitly. Unfortunately I can't remember the reason.

Can you elaborate on that?

Thanks.

Maybe it's a better idea after all if I post my code, and you tell me
whether it's okay or not. The function is supposed to create a string
from an integer holding the formatted size:

Glib::ustring FileBrowser::get_file_size( const boostfs::path& path )
{
Glib::ustring str_size;

try
{
if( boostfs::is_directory(path) )
return "0";

boost::intmax_t size = boostfs::file_size( path );

const int KILO_BYTE = 1024;
const int MEGA_BYTE = KILO_BYTE * 1024;
const int GIGA_BYTE = MEGA_BYTE * 1024;

if( size >= GIGA_BYTE )
{
size /= GIGA_BYTE;
str_size = boost::lexical_cast<Glib::ustring>(size) + " GB";
}
else if( size >= MEGA_BYTE )
{
size /= MEGA_BYTE;
str_size = boost::lexical_cast<Glib::ustring>(size) + " MB";
}
else if( size >= KILO_BYTE )
{
size /= KILO_BYTE;
str_size = boost::lexical_cast<Glib::ustring>(size) + " KB";
}
else
{
str_size = boost::lexical_cast<Glib::ustring>(size) + " B";
}
}
catch( const boostfs::filesystem_error& e )
{
std::cerr << e.what() << std::endl;
}

return str_size;
}

By the way, it would be cool if the file size wasn't reduced to a
rounded integer, but a float or double has too many digits.
Any idea how I can trim them to only one digit behind the dot, e.g.:

12.3 MB instead of 12.3xxxxxxx MB or such.
 
J

Joe C

Matthias Kaeppler said:
Maybe it's a better idea after all if I post my code, and you tell me
whether it's okay or not. The function is supposed to create a string from
an integer holding the formatted size:

Glib::ustring FileBrowser::get_file_size( const boostfs::path& path )
{
Glib::ustring str_size;

try
{
if( boostfs::is_directory(path) )
return "0";

boost::intmax_t size = boostfs::file_size( path );

const int KILO_BYTE = 1024;
const int MEGA_BYTE = KILO_BYTE * 1024;
const int GIGA_BYTE = MEGA_BYTE * 1024;

if( size >= GIGA_BYTE )
{
size /= GIGA_BYTE;
str_size = boost::lexical_cast<Glib::ustring>(size) + " GB";
}
else if( size >= MEGA_BYTE )
{
size /= MEGA_BYTE;
str_size = boost::lexical_cast<Glib::ustring>(size) + " MB";
}
else if( size >= KILO_BYTE )
{
size /= KILO_BYTE;
str_size = boost::lexical_cast<Glib::ustring>(size) + " KB";
}
else
{
str_size = boost::lexical_cast<Glib::ustring>(size) + " B";
}
}
catch( const boostfs::filesystem_error& e )
{
std::cerr << e.what() << std::endl;
}

return str_size;
}

By the way, it would be cool if the file size wasn't reduced to a rounded
integer, but a float or double has too many digits.
Any idea how I can trim them to only one digit behind the dot, e.g.:

12.3 MB instead of 12.3xxxxxxx MB or such.

Matthias, I made the following function to print filesize formated like 625
b, 1.34 Kb, 12.8 Kb, 16.3 Mb, 4.23 Gb, etc. to fit in a table. Just send
the filesize as a function argument and the function couts the text. I'd be
easy enough to modify the function to return a string.

Sorry if my long lines don't print very well...

void printFileSize(unsigned long int lof_in){
cout.precision(3);
cout << setw(4) << setfill(' ');
(lof_in < (1 << 10))
? (cout << lof_in << " b\t")
: (lof_in < (1 << 20))
? (cout << (static_cast<float>(lof_in)/(1 << 10)) << " Kb\t")
: (lof_in < (1 << 30))
? (cout << (static_cast<float>(lof_in)/(1 << 20)) << "
Mb\t" )
: (cout << (static_cast<float>(lof_in)/(1 << 30)) << "
Gb\t");
}
 
M

Matthias Kaeppler

Joe said:
Matthias, I made the following function to print filesize formated like 625
b, 1.34 Kb, 12.8 Kb, 16.3 Mb, 4.23 Gb, etc. to fit in a table. Just send
the filesize as a function argument and the function couts the text. I'd be
easy enough to modify the function to return a string.

Sorry if my long lines don't print very well...

void printFileSize(unsigned long int lof_in){
cout.precision(3);
cout << setw(4) << setfill(' ');
(lof_in < (1 << 10))
? (cout << lof_in << " b\t")
: (lof_in < (1 << 20))
? (cout << (static_cast<float>(lof_in)/(1 << 10)) << " Kb\t")
: (lof_in < (1 << 30))
? (cout << (static_cast<float>(lof_in)/(1 << 20)) << "
Mb\t" )
: (cout << (static_cast<float>(lof_in)/(1 << 30)) << "
Gb\t");
}

Ah, of course, the std::cout::precision thing is the key. Thanks a lot
for that function Joe!
 
M

Matthias Kaeppler

Joe said:
Matthias, I made the following function to print filesize formated like 625
b, 1.34 Kb, 12.8 Kb, 16.3 Mb, 4.23 Gb, etc. to fit in a table. Just send
the filesize as a function argument and the function couts the text. I'd be
easy enough to modify the function to return a string.

Sorry if my long lines don't print very well...

void printFileSize(unsigned long int lof_in){
cout.precision(3);
cout << setw(4) << setfill(' ');
(lof_in < (1 << 10))
? (cout << lof_in << " b\t")
: (lof_in < (1 << 20))
? (cout << (static_cast<float>(lof_in)/(1 << 10)) << " Kb\t")
: (lof_in < (1 << 30))
? (cout << (static_cast<float>(lof_in)/(1 << 20)) << "
Mb\t" )
: (cout << (static_cast<float>(lof_in)/(1 << 30)) << "
Gb\t");
}

Hmmm, based on your code, I have changed mine to look like this:

Glib::ustring FileBrowser::get_file_size( const boostfs::path& path )
{
std::eek:stringstream sstream;
sstream.precision( 2 );

try
{
if( boostfs::is_directory(path) )
return "0";

boost::intmax_t size = boostfs::file_size( path );

if( size >= GIGA_BYTE )
{
sstream << (static_cast<float>(size) / GIGA_BYTE);
sstream << " GB";
}
else if( size >= MEGA_BYTE )
{
sstream << (static_cast<float>(size) / MEGA_BYTE);
sstream << " MB";
}
else if( size >= KILO_BYTE )
{
sstream << (static_cast<float>(size) / KILO_BYTE);
sstream << " KB";
}
else
{
sstream << size;
sstream << " B";
}
}
catch( const boostfs::filesystem_error& e )
{
std::cerr << e.what() << std::endl;
}

return sstream.str();
}

However, it sometimes prints garbage, like "1.7e+02 KB" for a file which
is only a couple of KB large and I don't find my error.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,038
Latest member
OrderProperKetocapsules

Latest Threads

Top