Использование Net:: FTP gettextfile с недопустимыми символами (ASCII-8BIT против UTF-8)

У меня есть процесс, который извлекает плоский файл из мэйнфрейма через FTP. Обычно это нормально работает, но время от времени файл будет содержать что-то характерное. Если я попытаюсь получить файл с акцентом, весь процесс завершится с ошибкой: Encoding::UndefinedConversionError: "\x88" from ASCII-8BIT to UTF-8

Это использование метода Net::FTP gettextfile. Многие люди предлагают просто переключиться на getbinaryfile - это позволит мне загрузить файл, но в результате получившийся файл - это то, что я больше не могу разобрать (говорит он в UTF-8, но содержимое не имеет смысла).

Есть ли способ просто извлечь и сохранить файл как ASCII без использования рельсов, автоматически преобразующих вывод в UTF-8? Здесь мой код:

Net::FTP.open(config['host']) do |ftp|
  Rails.logger.info("FTP Connection established")

  ftp.login(config['user'], config['password'])
  Rails.logger.info("Login Successful")

  ftp.gettextfile("'#{config['es_in']}'", "data/es-in.#{Time.now.utc.strftime("%Y%m%d-%H%M%S")}")
  ftp.gettextfile("'#{config['ca_in']}'", "data/ca-in.#{Time.now.utc.strftime("%Y%m%d-%H%M%S")}")

  Rails.logger.info("Download(s) completed, terminating connection.")
end

Ответ 1

Если я правильно помню, текстовые файлы в FTP-dom являются ASCII-7bit и не могут содержать символы с верхним битом, AKA ASCII-8BIT. Акцентированные символы, даже в расширенных ASCII или 8BIT, или все, что мы хотим назвать чем-то выше 0x7F, должны быть переданы в двоичном режиме.

От FTP RFC:

   ASCII

     The ASCII character set is as defined in the ARPA-Internet
     Protocol Handbook.  In FTP, ASCII characters are defined to be
     the lower half of an eight-bit code set (i.e., the most
     significant bit is zero).

Итак, вы, вероятно, должны использовать getbinaryfile.

Основное практическое различие между ними состоит в том, что двоичный режим не будет выполнять переводы на конец строки. Если исходная система основана на ECDIC или альтернативном размере слова, gettextfile переведет файл на лету в ASCII. Встречащие символы, которые не в ожидаемой кодировке, могут легко вызвать проблему, которую вы видите.

Если файл не имеет смысла после передачи с использованием getbinaryfile, он может быть в альтернативном коде, чем UTF8 на мэйнфрейме. Вам нужно будет выяснить, какой набор кодов находится в этой системе, и открыть файл с соответствующими настройками кодировки после загрузки. Вы можете использовать команду file в системах * nix, чтобы получить обоснованное предположение о кодировке файлов, но это не исчерпывающий тест и может быть введен в заблуждение. Поскольку файл поступает с мэйнфрейма, он может использовать другой формат слова, такой как UTF-16BE, UTF-32LE или быть закодированным в EBCDIC. В этом случае работа с альтернативными ОС и аппаратными средствами становится очень раздражающей.

Без примеров текста, первых двух байтов файла и выборки текста в шестнадцатеричном дампе вам сложно помочь.

И, после всего этого, было бы проще использовать cURL или Curb gem для извлечения файла. cURL очень гибкий и мощный и может предоставить вам необходимые инструменты.