【问题标题】:Encoding::UndefinedConversionError: "\xA8" from ASCII-8BIT to UTF-8 (SFTP)编码::UndefinedConversionError: "\xA8" 从 ASCII-8BIT 到 UTF-8 (SFTP)
【发布时间】:2014-02-12 20:47:07
【问题描述】:

使用 Net-SFTP gem、Ruby 2 和 Rails 4

我编写了在纯 ruby​​ 中工作的代码,但是将我的代码复制到了 rails,现在我得到了:

Encoding::UndefinedConversionError: "\xA8" from ASCII-8BIT to UTF-8

我可以在我的代码中进行哪些更改以使其正常工作?

def self.get_recent_file(ftp_file, local_file)
    Net::SFTP.start(Config::A_FTP[:domain], Config::A_FTP[:username], :password => Config::A_FTP[:password]) do |sftp|
      sftp.download!(ftp_file, local_file)
    end
  end

日志

Encoding::UndefinedConversionError: "\xA8" from ASCII-8BIT to UTF-8
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/operations/download.rb:339:in `write'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/operations/download.rb:339:in `write'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/operations/download.rb:339:in `on_read'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/request.rb:87:in `call'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/request.rb:87:in `respond_to'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/session.rb:948:in `dispatch_request'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/session.rb:911:in `when_channel_polled'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/channel.rb:311:in `call'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/channel.rb:311:in `process'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:222:in `block in preprocess'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:222:in `each'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:222:in `preprocess'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:205:in `process'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `block in loop'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `loop'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `loop'
... 13 levels...
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:222:in `preprocess'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:205:in `process'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `block in loop'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `loop'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `loop'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/session.rb:802:in `loop'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/session.rb:787:in `connect!'
    from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp.rb:32:in `start'

GEM 日志中引用的代码:

https://github.com/net-ssh/net-sftp/blob/master/lib/net/sftp/operations/download.rb#L339

# Called when a read from a file finishes. If the read was successful
  # and returned data, this will call #download_next_chunk to read the
  # next bit from the file. Otherwise the file will be closed.
  def on_read(response)
    entry = response.request[:entry]

    if response.eof?
      update_progress(:close, entry)
      entry.sink.close
      request = sftp.close(entry.handle, &method(:on_close))
      request[:entry] = entry
    elsif !response.ok?
      raise "read #{entry.remote}: #{response}"
    else
      entry.offset += response[:data].bytesize
      update_progress(:get, entry, response.request[:offset], response[:data])
      entry.sink.write(response[:data]) # <~~ Line#339
      download_next_chunk(entry)
    end
  end

【问题讨论】:

标签: ruby-on-rails ruby net-sftp


【解决方案1】:

这对我有帮助:

def self.get_recent_file(ftp_file, local_file)
  local_io = File.new(local_file, mode: 'w', encoding: 'ASCII-8BIT')
  Net::SFTP.start(Config::A_FTP[:domain], Config::A_FTP[:username], :password => Config::A_FTP[:password]) do |sftp|
    sftp.download!(ftp_file, local_io)
  end
  local_io.close
end

【讨论】:

  • local_io.close 对我来说是不必要的。
【解决方案2】:

user72136 的回答和this question 的回答对我有用(我的远程文件甚至不是 ASCII):

def self.get_recent_file(ftp_file, local_file)
  local_io = File.new(local_file, mode: 'wb')
  Net::SFTP.start(Config::A_FTP[:domain], Config::A_FTP[:username], :password => Config::A_FTP[:password]) do |sftp|
    sftp.download!(ftp_file, local_io)
  end
  local_io.close
end

【讨论】:

  • 这是正确答案。远程文件不是 ASCII,接受的答案会将它们转换为 ASCII,这可能会导致更多问题。
【解决方案3】:

正如line#339 所显示的那样

entry.sink.write(response[:data])

把它改成:

entry.sink.write(response[:data].force_encoding('ASCII-8BIT').encode('UTF-8'))

【讨论】:

  • 我试图避免编辑 gem,还有其他想法吗?
  • @user2012677 不知道亲爱的!
【解决方案4】:

换行-

sftp.download!(ftp_file, local_file)

sftp.download!(ftp_file, local_file).to_s.encode('UTF-8', {:invalid => :replace, :undef => :replace, :replace => '?'})

【讨论】:

  • 您的建议不起作用,因为它会将文件保存到驱动器。如果它只是一个字符串,您的解决方案可以工作。谢谢
【解决方案5】:

这个问题是由 Ruby 2.0 版本之后使用 UTF-8 编码默认打开文本文件的方式产生的。您可以在哪里打开文件:

local_file = Tempfile.new(encoding: 'ascii-8bit')
#or another thing to do is to switch to binary-mode
local_file = Tempfile.new
local_file.binmode

你也可以像这样打开一个二进制文件:

local_file = File.open('/tmp/local_file', 'wb')

您可以做的另一个解决方案是将文件路径而不是打开的文件传递给 gem-code:

def self.get_recent_file(ftp_file, local_file)
  Net::SFTP.start(Config::A_FTP[:domain], Config::A_FTP[:username], :password => Config::A_FTP[:password]) do |sftp|
    sftp.download!(ftp_file, local_file.path)
  end
end

【讨论】:

    猜你喜欢
    • 2014-08-26
    • 2017-10-02
    • 2013-05-01
    • 1970-01-01
    • 2017-04-20
    • 1970-01-01
    • 1970-01-01
    • 2014-06-12
    • 1970-01-01
    相关资源
    最近更新 更多