0

I have been using to split the file content based on the character count, since one of my application which doesn't support for any number of characters. So I have to split the content based on the character count and update it multiple times based on the total character count.

c_max = 50000
f = File.new(filename)
u_count = (c_count / c_max.to_f).ceil
i = 1
while i <= u_count do
    u_characters = f.sysread(c_max)
    # do stuffs
    i+=1
end

But its not working when I use strings instead of filename.

content=File.read(filename)
#doing some stuffs on the contents 
irb(main):006:0> content.sysread(10)
NoMethodError: undefined method `sysread' for #<String:0x7f5f2eedd368>
        from (irb):6
        from :0
irb(main):007:0>
2
  • 2
    Obviously, there's no method sysread on strings. And I have no idea what is it that you're trying to accomplish with that. Commented Jun 6, 2017 at 14:04
  • Can you use StringIO instead of plain String? Commented Jun 6, 2017 at 14:06

2 Answers 2

2

If you are trying to limit the number of characters IO#each_line can help you with this e.g.

c_max = 100
File.open(filename) do |file|
  file.each_line(c_max) do |characters|
    # characters is now a string that is 100 characters long
    # do something with characters
  end
end

Or to handle a String you can make it a StringIO and #each_line will work too (Please note String#each_line will not work as it only accepts a separator (String) and not a character limit (Fixnum) this is why we need StringIO)

s = "THIS IS A STRING"
StringIO.open(s) do |strio|
  strio.each_line(2) do |characters|
    # characters is now a string that is 2 characters long
    # do something with characters
  end
end    

So let's handle both options Update: (Based on comment discussion with @CarySwoveland - Thanks for pushing me further)

def do_stuff(line)
  # common functionality goes here 
  puts line
end

# return is a StringIO or File
# leaks file descriptor handle as you wish
def my_method(s,sep_or_char_limit=100)
  target = s.to_s # leverage a little duck typing
  target_class = File.file?(target) ? File : StringIO
  target_class.open(target) do |io|
    io.each_line(sep_or_char_limit, &method(:do_stuff))
  end
end 

Since this uses Enumerator functionality it will also help with memory consumption since the whole File need not be read into memory first or the whole String does not need to be split into a temporary Array.

There is additional hidden functionality here as well. You asked for limitation by characters but this will also allow for a separator if you prefer. e.g.

# Using a Character Limit
my_method("THIS IS A STRING",2)
# TH
# IS
#  I
# S
# A
# ST
# RI
# NG


# Using a separator 
my_method("THIS IS A STRING",' ')
# THIS 
# IS 
# A 
# STRING
Sign up to request clarification or add additional context in comments.

9 Comments

I like. A variant for the body of my_method: (File.file?(s) ? File.open(s) : StringIO.new(s)).each_line(sep_or_char_limit, &method(:do_stuff)). This omits your target = s.to_s`, as I didn't understand why that's needed.
@CarySwoveland File.open suggests that I also need to close where as foreach will close the file on block termination. the to_s is there for edge cases say my_method([1,2,3,4,5],',') this will not fail because the true definition from a documentation standpoint is simply any object that has a public to_s method
I considered that but the file will be closed when the method exits. I could of course begin with target = s.to_s and change s to target in what I suggested.
In your update I like your use of open (didn't know about that) and the fact that you made the only difference the class, rather than the method.
@CarySwoveland I aim to please and our discussion made for a better technical implementation (DRY and consistent return value). Thanks :)
|
1

The problem is that a String object doesn't have a sysread method. To get the first n characters of a String object you can use String slice(range):

content[0...10]

or slice(start, length):

content[0, 10]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.