Pretty File Size in Ruby

Pretty file size in Ruby?

How about the Filesize gem ? It seems to be able to convert from bytes (and other formats) into pretty printed values:

example:

Filesize.from("12502343 B").pretty      # => "11.92 MiB"

http://rubygems.org/gems/filesize

Getting accurate file size in megabytes?

Try:

compressed_file_size = File.size("Compressed/#{project}.tar.bz2").to_f / 2**20
formatted_file_size = '%.2f' % compressed_file_size

One-liner:

compressed_file_size = '%.2f' % (File.size("Compressed/#{project}.tar.bz2").to_f / 2**20)

or:

compressed_file_size = (File.size("Compressed/#{project}.tar.bz2").to_f / 2**20).round(2)

Further information on %-operator of String:
http://ruby-doc.org/core-1.9/classes/String.html#M000207


BTW: I prefer "MiB" instead of "MB" if I use base2 calculations (see: http://en.wikipedia.org/wiki/Mebibyte)

Convert human readable file size to bytes in ruby

There's filesize (rubygems)

It's quite trivial to write your own:

module ToBytes
def to_bytes
md = match(/^(?<num>\d+)\s?(?<unit>\w+)?$/)
md[:num].to_i *
case md[:unit]
when 'KB'
1024
when 'MB'
1024**2
when 'GB'
1024**3
when 'TB'
1024**4
when 'PB'
1024**5
when 'EB'
1024**6
when 'ZB'
1024**7
when 'YB'
1024**8
else
1
end
end
end

size_string = "10KB"
size_string.extend(ToBytes).to_bytes
=> 10240

String.include(ToBytes)
"1024 KB".to_bytes
=> 1048576

If you need KiB, MiB etc then you just add multipliers.

How can I find the size of an uploaded file in Ruby on Rails?


File.size(doc.filename)

Just throw the name of the file into the curly brackets and you should be set.

If you want KB/MB use:

number_to_human_size(File.size(doc.filename))

EDIT:

You can use the exact path or Pathname

1.9.3p125 :005 > x=Pathname.new("/usr/bin/ruby")
=> #<Pathname:/usr/bin/ruby>
1.9.3p125 :006 > File.size(x)
=> 5488

For extension:

File.extname("test.rb")         #=> ".rb"

Stop file write if file size exceeds 500KB ruby on rails

IO#read, takes a bytes argument, so you can specify the size of what you want to read from IO as below:

require 'open-uri'
open('temp/demo.doc', 'wb') do |file|
file << open('http://example.com/demo.doc').read(500000)
end

you can also play with things like file.stat.size but given you are piping directly to file you would have to do more things to get this to work.

Ruby: Length of a line of a file in bytes?

IO#gets works the same as if you were capturing input from the command line: the "Enter" isn't sent as part of the input; neither is it passed when #gets is called on a File or other subclass of IO, so the numbers are definitely not going to match up.

See the relevant Pickaxe section

May I enquire why you're so concerned about the line lengths summing to the file size? You may be solving a harder problem than is necessary...

Aha. I think I get it now.

Lacking a handy iPod (or any other sort, for that matter), I don't know if you want exactly 4K chunks, in which case IO#read(4000) would be your friend (4000 or 4096?) or if you're happier to break by line, in which case something like this ought to work:

class Chunkifier
def Chunkifier.to_chunks(path)
chunks, current_chunk_size = [""], 0
File.readlines(path).each do |line|
line.chomp! # strips off \n, \r or \r\n depending on OS
if chunks.last.size + line.size >= 4_000 # 4096?
chunks.last.chomp! # remove last line terminator
chunks << ""
end
chunks.last << line + "\n" # or whatever terminator you need
end
chunks
end
end

if __FILE__ == $0
require 'test/unit'
class TestFile < Test::Unit::TestCase
def test_chunking
chs = Chunkifier.to_chunks(PATH)
chs.each do |chunk|
assert 4_000 >= chunk.size, "chunk is #{chunk.size} bytes long"
end
end
end
end

Note the use of IO#readlines to get all the text in one slurp: #each or #each_line would do as well. I used String#chomp! to ensure that whatever the OS is doing, the byts at the end are removed, so that \n or whatever can be forced into the output.

I would suggest using File#write, rather than #print or #puts for the output, as the latter have a tendency to deliver OS-specific newline sequences.

If you're really concerned about multi-byte characters, consider taking the each_byte or unpack(C*) options and monkey-patching String, something like this:

class String
def size_in_bytes
self.unpack("C*").size
end
end

The unpack version is about 8 times faster than the each_byte one on my machine, btw.

Converting filesize string to kilobyte equivalent in Rails


def quota_convert
@regex = /([0-9]+) (.*)s?/
@sizes = "kilobytes megabytes gigabytes"
m = self.quota.match(@regex)
if @sizes.include? m[2]
m[1].to_f.send(m[2])
end
end
  • Added ? for optional plural in the regex.
  • Changed @sizes to a string of plurals.
  • Convert m[1] (the number to a float).
  • Send the message m[2] directly

How to stub file size on Active Storage test? (Test::Unit)

I read the code from your project, and I see that you've come up with an interesting solution, but here's another that matches your requirements.

Step 1 - Add mocha

Mocha is the de facto stubbing library for MiniTest fans, so add it to your Gemfile like so.

group :test do
gem 'mocha'
end

Then run bundle install and require mocha in your test helper like so:

# test/test_helper.rb

ENV['RAILS_ENV'] ||= 'test'

require_relative '../config/environment'
require 'rails/test_help'

# add this line
require 'mocha/minitest'

class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
end

Step 2 - Create a dummy test file

Place a small file named 'test.png' in test/fixtures/files/. Note that my file is around 20KB in size, it's pretty small.

Step 3 - Add a unit test

Add the following to test/models/page_test.rb:

test 'file has max size' do
# get the path of the file
fixture_path = File.join(Rails.root, 'test', 'fixtures', 'files', 'test.png')

# open the file
fixture_file = File.open(fixture_path)

# stub the file size to 21 MB
fixture_file.stubs(:size).returns(21.megabytes)

# attach the file to your @page instance
@page.file.attach(io: fixture_file, filename: 'test.png')

# the record should now be invalid
refute @page.valid?

# it should not have an attachment
refute @page.file.attached?

# assert the error message matches a regex
assert_match /is too big/, @page.errors[:file].to_s
end

Step 4 - Test inside the maximum filesize boundary

Let's make sure that a file of 20MB can be accepted by adding the following to test/models/page_test.rb:

test 'file with valid size' do
# get the path of the file
fixture_path = File.join(Rails.root, 'test', 'fixtures', 'files', 'test.png')

# open the file
fixture_file = File.open(fixture_path)

# stub the file size to 20 MB
fixture_file.stubs(:size).returns(20.megabytes)

# attach the file to your @page instance
@page.file.attach(io: fixture_file, filename: 'test.png')

# the record should now be valid
assert @page.valid?

# it should have an attachment
assert @page.file.attached?

# probably unnecessary, but let's test that there are no errors on @page
assert_empty @page.errors[:file]
end

Step 5 - Add a controller test for the happy path

Let's add a controller test for the happy path:

test 'should update page' do
# fixture_file_upload knows where the fixtures folder is
# and makes sure we have a correctly signed file
fixture_file = fixture_file_upload('files/test.png', 'image/png')

# we need to stub the byte_size of any instance of ActiveStorage::Blob
# as that is what our validations are going to be run against
ActiveStorage::Blob.any_instance.stubs(:byte_size).returns(20.megabytes)

# make sure our ActiveStorage records are created
assert_difference ['ActiveStorage::Blob.count', 'ActiveStorage::Attachment.count'] do
# add our fixture file into the params
patch page_url, params: { page: { file: fixture_file } }
end

# make sure we are redirected to the right place
assert_redirected_to page_url
end

Step 6 - Add a controller test for the sad path

Time to test upload failure:

test 'should render edit template when update fails' do
# like before, we get correctly formatted test file by calling
# fixture_file_upload method and passing in the test file
fixture_file = fixture_file_upload('files/test.png', 'image/png')

# stub the byte_size to be 21MB
ActiveStorage::Blob.any_instance.stubs(:byte_size).returns(21.megabytes)

# make sure zero ActiveStorage records are created
assert_no_difference ['ActiveStorage::Blob.count', 'ActiveStorage::Attachment.count'] do
# send the request
patch page_url, params: { page: { file: fixture_file } }
end

# check the response body for an error message
assert_match /is too big/, response.body.to_s
end

That's it. Hope it helps.



Related Topics



Leave a reply



Submit