Перенос данных между разными операционными системами — классическая задача при автоматизации обмена данными или деплое приложений. Когда нам необходимо передать файл из системы Windows в систему Linux программным путем, мы сталкиваемся с тем, что стандартные средства копирования (например, библиотека shutil) не работают напрямую через сеть, если целевой каталог не «расшарен» через протоколы типа Samba или NFS.
В этой статье мы подробно разберем, как реализовать надежный механизм передачи файлов, используя протоколы SSH и SFTP, которые являются стандартом безопасности для Linux-систем. Мы рассмотрим основной код, разберем типичные ошибки с правами доступа и узнаем, как подготовить окружение даже в условиях отсутствия интернета.
Наиболее гибким и популярным способом взаимодействия с Linux-серверами из Python является библиотека paramiko. Она реализует протокол SSHv2 и предоставляет удобный интерфейс для работы с SFTP (Secure File Transfer Protocol). Рассмотрим пошагово, как настроить соединение и отправить файл.
Для начала проанализируем базовый алгоритм работы скрипта:
Рассмотрим пример рабочего кода, который позволяет передать файлы баз данных и геоданных (в нашем примере это файлы .dbf, .shp, .shx):
import paramiko
# Инициализируем SSH-клиент
ssh = paramiko.SSHClient()
# Настраиваем политику автоматического добавления ключа сервера
# (внимание: для промышленных систем лучше использовать проверку ключа)
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# Устанавливаем соединение с Linux-машиной
ssh.connect('10.255.255.99', username='permyakov', password='password')
# Открываем SFTP-сессию
ftp = ssh.open_sftp()
# Определяем пути и отправляем файлы
# Пример для нескольких файлов
files_to_upload = [
('C:\\Users\\svc-app\\AppData\\Local\\Temp\\Paramico\\Work.dbf', '/usr/etc/geofiles/Work.dbf'),
('C:\\Users\\svc-app\\AppData\\Local\\Temp\\Paramico\\Work.shp', '/usr/etc/geofiles/Work.shp'),
('C:\\Users\\svc-app\\AppData\\Local\\Temp\\Paramico\\Work.shx', '/usr/etc/geofiles/Work.shx')
]
for localpath, remotepath in files_to_upload:
print(f"Отправка {localpath} в {remotepath}...")
ftp.put(localpath, remotepath)
# Закрываем ресурсы
ftp.close()
ssh.close()
В этом примере метод ftp.put(localpath, remotepath) берет файл с вашего локального диска на Windows и записывает его по указанному абсолютному пути на Linux-сервере. Важно убедиться, что у пользователя, под которым вы подключаетесь, есть права на запись в целевую папку.
Часто после успешного выполнения скрипта пользователи сталкиваются с ошибкой PermissionError: [Errno 13] Permission denied. Это происходит, если файл на Linux уже существует, но ваш пользователь не имеет прав на его перезапись, либо у вас нет прав на создание файлов в этой директории.
Выясним причину: в Linux права доступа жестко разграничены. Если вы загружаете файлы в системные папки, такие как /usr/etc/, вам может потребоваться изменить права доступа к целевой папке или самим файлам. Вы можете сделать это прямо из Python, выполнив команду chmod через тот же SSH-объект:
# Пример смены прав доступа на папку перед копированием
ssh.exec_command('chmod 777 /usr/etc/geofiles/')
# Или смена прав на конкретный файл после его загрузки
ssh.exec_command('chmod 644 /usr/etc/geofiles/Work.dbf')
Также в библиотеке paramiko предусмотрен встроенный метод для работы с правами через SFTP-объект: ftp.chmod(remotepath, 0o755). Использование восьмеричной системы счисления (префикс 0o) позволяет задавать права в привычном для Linux формате.
Разберем ситуацию, когда целевая Windows-машина, с которой должен работать скрипт, не имеет доступа к интернету. Просто скопировать папку site-packages — это рабочий, но не самый надежный метод, так как многие библиотеки (например, cryptography, используемая в paramiko) содержат скомпилированные C-компоненты.
Правильный алгоритм установки в изолированной среде выглядит следующим образом:
pip download paramiko -d C:\packages
C:\packages на целевую машину.pip install --no-index --find-links=C:\packages paramiko
Это гарантирует, что все бинарные зависимости будут установлены корректно и скрипт не «упадет» из-за отсутствия какого-либо системного модуля.
Если вам кажется работа с open_sftp() излишне громоздкой, проанализируем библиотеку scp. Это высокоуровневая обертка над paramiko, которая имитирует поведение стандартной консольной утилиты SCP. Она работает быстрее SFTP при передаче больших объемов данных.
from paramiko import SSHClient, AutoAddPolicy
from scp import SCPClient
ssh = SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(AutoAddPolicy())
ssh.connect('192.168.1.100', username='user', password='password')
# Используем контекстный менеджер для автоматического закрытия
with SCPClient(ssh.get_transport()) as scp:
scp.put('local_file.txt', '/remote/path/file.txt')
Такой подход делает код чище и избавляет от необходимости вручную закрывать сессии передачи данных.
При переносе текстовых файлов (например, скриптов .sh или конфигураций) из Windows в Linux помните о разнице в кодировках и символах окончания строк. Windows использует CRLF (\r\n), а Linux — LF (\n). Если вы скопируете скрипт «как есть», он может выдать ошибку при запуске в Linux.
Рекомендуется перед отправкой нормализовать строки:
with open('script.sh', 'r') as f:
content = f.read().replace('\r\n', '\n')
with open('script_linux.sh', 'w', newline='\n') as f:
f.write(content)
# Теперь отправляем script_linux.sh
Для критически важных файлов обязательно проверяйте целостность данных после передачи. Проанализируем, как сравнить контрольные суммы:
import hashlib
def get_md5(filename):
hash_md5 = hashlib.md5()
with open(filename, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
# На Linux проверяем через SSH
stdin, stdout, stderr = ssh.exec_command('md5sum /usr/etc/geofiles/Work.dbf')
remote_md5 = stdout.read().decode().split()[0]
if get_md5('Work.dbf') == remote_md5:
print("Файл передан без ошибок")
else:
print("Ошибка целостности данных!")
Используя предложенные методы, вы сможете построить отказоустойчивую систему автоматизированного обмена файлами между гетерогенными системами, учитывая вопросы безопасности, прав доступа и специфики сетевых настроек заказчика.