Net::FTP puttextfile question

Discussion in 'Ruby' started by Jeff, Apr 4, 2007.

  1. Jeff

    Jeff Guest

    I'm trying to use the Net::FTP class to send a text file to my FTP
    server, but I don't have an actual text file to send. Instead I want
    to send it a multi-line string as my "file". (I'm using Builder to
    generate an XML file and I don't want to have to physically save it to
    a file before sending it.)

    The Net::FTP class has a method called puttextfile that seems to be
    defined like this:

    def puttextfile(localfile, remotefile = File.basename(localfile),
    &block)

    but I don't have a local filename to provide. Is there anything I can
    use that would substitute for one?

    I tried to use a StringIO object, hoping to use that as my
    "localfile":

    s = StringIO.new(xml_data)

    but when I try to send it like this:

    Net::FTP.open("domain.com", "username", "secret") do |ftp|
    ftp.puttextfile(s, '\data\file.xml"')
    end

    I get this error:

    TypeError: can't convert StringIO into String
    from c:/ruby/lib/ruby/1.8/net/ftp.rb:571:in `open'
    from c:/ruby/lib/ruby/1.8/net/ftp.rb:571:in `puttextfile'
    from (irb):33
    from c:/ruby/lib/ruby/1.8/net/ftp.rb:115:in `open'
    from (irb):32

    Obviously it wants a filename, and I'm giving it the actual IO object
    instead. .NET had the concept of IO streams, and I was hoping to use
    something like that here, but I can't figure out how.

    Any ideas?

    Thanks!
    Jeff
     
    Jeff, Apr 4, 2007
    #1
    1. Advertising

  2. Jeff

    Jeff Guest

    On Apr 3, 8:26 pm, "Jeff" <> wrote:
    > I'm trying to use the Net::FTP class to send a text file to my FTP
    > server, but I don't have an actual text file to send. Instead I want
    > to send it a multi-line string as my "file". (I'm using Builder to
    > generate an XML file and I don't want to have to physically save it to
    > a file before sending it.)
    >
    > The Net::FTP class has a method called puttextfile that seems to be
    > defined like this:
    >
    > def puttextfile(localfile, remotefile = File.basename(localfile),
    > &block)
    >
    > but I don't have a local filename to provide. Is there anything I can
    > use that would substitute for one?


    I ended up subclassing and providing the functionality myself.

    In case it helps anyone, here's what I came up with: two methods,
    get_text_lines and send_text_lines. See below for complete source
    (it's not too long). Suggestions for making the code more elegant are
    definitely welcome.
    Jeff

    require 'net/ftp'

    class JeffFTP < Net::FTP

    # Sends a collection of lines to be saved in a file on the server
    # lines can be an array, or anything responding to #each
    def send_text_lines(lines, remotefile, &block) # :yield: line
    storlines_from_array("STOR " + remotefile, lines, &block)
    end

    # Gets a file from the server as a collection of text lines.
    # If you don't provide a block, it will return an array of lines.
    # If you provide a block, each line will be passed to the block,
    # and the return value will be an empty array.
    # Large files should use the block form.
    def get_text_lines(remotefile, &block) # :yield: line
    lines = []
    retrlines("RETR " + remotefile) do |line|
    if block
    yield(line)
    else
    lines << line
    end
    end
    lines
    end

    private

    def storlines_from_array(cmd, lines, &block) # :yield: line
    synchronize do
    voidcmd("TYPE A")
    conn = transfercmd(cmd)
    lines.each do |line|
    conn.write(line)
    yield(line) if block
    end
    conn.close
    voidresp
    end
    end

    end
     
    Jeff, Apr 4, 2007
    #2
    1. Advertising

  3. On 4/3/07, Jeff <> wrote:
    > I'm trying to use the Net::FTP class to send a text file to my FTP
    > server, but I don't have an actual text file to send. Instead I want
    > to send it a multi-line string as my "file". (I'm using Builder to
    > generate an XML file and I don't want to have to physically save it to
    > a file before sending it.)
    >
    > The Net::FTP class has a method called puttextfile that seems to be
    > defined like this:
    >
    > def puttextfile(localfile, remotefile = File.basename(localfile),
    > &block)
    >
    > but I don't have a local filename to provide. Is there anything I can
    > use that would substitute for one?
    >
    > I tried to use a StringIO object, hoping to use that as my
    > "localfile":
    >
    > s = StringIO.new(xml_data)
    >
    > but when I try to send it like this:
    >
    > Net::FTP.open("domain.com", "username", "secret") do |ftp|
    > ftp.puttextfile(s, '\data\file.xml"')
    > end
    >
    > I get this error:
    >
    > TypeError: can't convert StringIO into String
    > from c:/ruby/lib/ruby/1.8/net/ftp.rb:571:in `open'
    > from c:/ruby/lib/ruby/1.8/net/ftp.rb:571:in `puttextfile'
    > from (irb):33
    > from c:/ruby/lib/ruby/1.8/net/ftp.rb:115:in `open'
    > from (irb):32
    >
    > Obviously it wants a filename, and I'm giving it the actual IO object
    > instead. .NET had the concept of IO streams, and I was hoping to use
    > something like that here, but I can't figure out how.
    >
    > Any ideas?


    Try turning the problem around and look at using open-uri instead of
    Net::FTP? This extends Kernel::eek:pen so that it accepts ftp and http
    urls as well as file names. This makes the ftp server look like a
    local file.

    So you'd do something like this (untested):

    require 'open-uri'

    open("ftp://user:/data/file.xml",'w') do | f |
    # write your data to the IO object f here
    end
    --
    Rick DeNatale

    My blog on Ruby
    http://talklikeaduck.denhaven2.com/
     
    Rick DeNatale, Apr 6, 2007
    #3
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    3
    Views:
    5,656
  2. Nico Grubert
    Replies:
    0
    Views:
    645
    Nico Grubert
    Nov 24, 2005
  3. Nico Grubert
    Replies:
    0
    Views:
    449
    Nico Grubert
    Nov 25, 2005
  4. Replies:
    2
    Views:
    151
  5. D. Buck
    Replies:
    2
    Views:
    493
    D. Buck
    Jun 29, 2004
Loading...

Share This Page