Подтвердить что ты не робот

Как я могу использовать FTP для перемещения файлов между каталогами?

У меня есть программа, которая должна переместить файл из одного каталога в другой на FTP-сервере. Например, файл находится в папке

ftp://1.1.1.1/MAIN/Dir1

и мне нужно переместить файл:

ftp://1.1.1.1/MAIN/Dir2

Я нашел пару статей, рекомендующих использовать команду Rename, поэтому я попробовал следующее:

    Uri serverFile = new Uri("ftp://1.1.1.1/MAIN/Dir1/MyFile.txt");
    FtpWebRequest reqFTP= (FtpWebRequest)FtpWebRequest.Create(serverFile);
    reqFTP.Method = WebRequestMethods.Ftp.Rename;
    reqFTP.UseBinary = true;
    reqFTP.Credentials = new NetworkCredential(ftpUser, ftpPass);
    reqFTP.RenameTo = "ftp://1.1.1.1/MAIN/Dir2/MyFile.txt";

    FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();

Но это, похоже, не работает - я получаю следующую ошибку:

Удаленный сервер возвратил ошибку: (550) Файл недоступен (например, файл не найден, нет доступа).

Сначала я думал, что это может относиться к разрешениям, но, насколько я вижу, у меня есть разрешения на весь FTP-сайт (он находится на моем локальном ПК, а uri разрешен на localhost).

Можно ли перемещать файлы между такими каталогами, а если нет, то как это возможно?

Чтобы обратиться к некоторым вопросам/предложениям, которые были подняты:

  • Я могу загрузить тот же файл из исходного каталога, поэтому он определенно существует (то, что я делаю, сначала загружает файл, а затем перемещает его в другое место).
  • Я могу получить доступ к ftp-сайту из браузера (как исходного, так и целевого каталога)
  • ftp-сервер работает под моим собственным экземпляром IIS на моей локальной машине.
  • Путь и регистр верны и особых символов нет.

Кроме того, я попытался установить путь к каталогу:

ftp://1.1.1.1/%2fMAIN/Dir1/MyFile.txt

Как для исходного, так и для целевого пути - но это тоже не имеет значения.

Я нашел эту статью, которая, по-видимому, подсказывает, что указание назначения как относительного пути поможет - оно не представляется возможным для указания абсолютного пути в качестве адресата.

reqFTP.RenameTo = "../Dir2/MyFile.txt";
4b9b3361

Ответ 1

MSDN кажется, что ваш путь считается относительным, и поэтому он пытается войти в FTP сервер, используя предоставленные учетные данные, затем устанавливает текущий каталог в каталог <UserLoginDirectory>/path. Если это не тот каталог, где находится ваш файл, вы получите ошибку 550.

Ответ 2

Имел ту же проблему и нашел другой способ решить проблему:

public string FtpRename( string source, string destination ) {
        if ( source == destination )
            return;

        Uri uriSource = new Uri( this.Hostname + "/" + source ), UriKind.Absolute );
        Uri uriDestination = new Uri( this.Hostname + "/" + destination ), UriKind.Absolute );

        // Do the files exist?
        if ( !FtpFileExists( uriSource.AbsolutePath ) ) {
            throw ( new FileNotFoundException( string.Format( "Source '{0}' not found!", uriSource.AbsolutePath ) ) );
        }

        if ( FtpFileExists( uriDestination.AbsolutePath ) ) {
            throw ( new ApplicationException( string.Format( "Target '{0}' already exists!", uriDestination.AbsolutePath ) ) );
        }

        Uri targetUriRelative = uriSource.MakeRelativeUri( uriDestination );


        //perform rename
        FtpWebRequest ftp = GetRequest( uriSource.AbsoluteUri );
        ftp.Method = WebRequestMethods.Ftp.Rename;
        ftp.RenameTo = Uri.UnescapeDataString( targetUriRelative.OriginalString );

        FtpWebResponse response = (FtpWebResponse)ftp.GetResponse(); 

        return response.StatusDescription; 

    }

Ответ 3

Мне удалось получить эту работу, но только с использованием пути, который существует на сервере, т.е. /DRIVELETTER:/FOLDERNAME/filename в RenameTo = "

Ответ 4

Что делать, если у вас есть только абсолютные пути?

Хорошо, я столкнулся с этим сообщением, потому что получал ту же ошибку. Ответ, похоже, заключается в использовании относительного пути, что не очень хорошо для решения моей проблемы, потому что я получаю пути к папкам как абсолютные строки пути.

Решения, которые я придумал на лету, но, по крайней мере, уродливые. Я сделаю это ответ wiki сообщества, и если у кого-то будет лучшее решение, не стесняйтесь редактировать это.

Поскольку я узнал об этом, у меня есть 2 решения.

  • Возьмите абсолютный путь от перехода к пути и преобразуйте его в относительный URL.

    public static string GetRelativePath(string ftpBasePath, string ftpToPath)
    {
    
        if (!ftpBasePath.StartsWith("/"))
        {
            throw new Exception("Base path is not absolute");
        }
        else
        {
            ftpBasePath =  ftpBasePath.Substring(1);
        }
        if (ftpBasePath.EndsWith("/"))
        {
            ftpBasePath = ftpBasePath.Substring(0, ftpBasePath.Length - 1);
        }
    
        if (!ftpToPath.StartsWith("/"))
        {
            throw new Exception("Base path is not absolute");
        }
        else
        {
            ftpToPath = ftpToPath.Substring(1);
        }
        if (ftpToPath.EndsWith("/"))
        {
            ftpToPath = ftpToPath.Substring(0, ftpToPath.Length - 1);
        }
        string[] arrBasePath = ftpBasePath.Split("/".ToCharArray());
        string[] arrToPath = ftpToPath.Split("/".ToCharArray());
    
        int basePathCount = arrBasePath.Count();
        int levelChanged = basePathCount;
        for (int iIndex = 0; iIndex < basePathCount; iIndex++)
        {
            if (arrToPath.Count() > iIndex)
            {
                if (arrBasePath[iIndex] != arrToPath[iIndex])
                {
                    levelChanged = iIndex;
                    break;
                }
            }
        }
        int HowManyBack = basePathCount - levelChanged;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < HowManyBack; i++)
        {
            sb.Append("../");
        }
        for (int i = levelChanged; i < arrToPath.Count(); i++)
        {
            sb.Append(arrToPath[i]);
            sb.Append("/");
        }
    
        return sb.ToString();
    }
    
    public static string MoveFile(string ftpuri, string username, string password, string ftpfrompath, string ftptopath, string filename)
    {
        string retval = string.Empty;
    
        FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(ftpuri + ftpfrompath + filename);
        ftp.Method = WebRequestMethods.Ftp.Rename;
        ftp.Credentials = new NetworkCredential(username, password);
        ftp.UsePassive = true;
        ftp.RenameTo = GetRelativePath(ftpfrompath, ftptopath) + filename;
        Stream requestStream = ftp.GetRequestStream();
    
    
        FtpWebResponse ftpresponse = (FtpWebResponse)ftp.GetResponse();
    
        Stream responseStream = ftpresponse.GetResponseStream();
    
        StreamReader reader = new StreamReader(responseStream);
    
        return reader.ReadToEnd();
    }
    

или...

  • Загрузите файл с пути "ftp from", загрузите его на путь "ftp to" и удалите его из пути "ftp from".

    public static string SendFile(string ftpuri, string username, string password, string ftppath, string filename, byte[] datatosend)
    {
        if (ftppath.Substring(ftppath.Length - 1) != "/")
        {
            ftppath += "/";
        }
        FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(ftpuri + ftppath + filename);
        ftp.Method = WebRequestMethods.Ftp.UploadFile;
        ftp.Credentials = new NetworkCredential(username, password);
        ftp.UsePassive = true;
        ftp.ContentLength = datatosend.Length;
        Stream requestStream = ftp.GetRequestStream();
        requestStream.Write(datatosend, 0, datatosend.Length);
        requestStream.Close();
    
        FtpWebResponse ftpresponse = (FtpWebResponse)ftp.GetResponse();
    
        return ftpresponse.StatusDescription;
    }
    public static string DeleteFile(string ftpuri, string username, string password, string ftppath, string filename)
    {
    
        FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(ftpuri + ftppath + filename);
        ftp.Method = WebRequestMethods.Ftp.DeleteFile;
        ftp.Credentials = new NetworkCredential(username, password);
        ftp.UsePassive = true;
    
        FtpWebResponse response = (FtpWebResponse)ftp.GetResponse();
    
        Stream responseStream = response.GetResponseStream();
    
        StreamReader reader = new StreamReader(responseStream);
    
        return reader.ReadToEnd();
    }
    public static string MoveFile(string ftpuri, string username, string password, string ftpfrompath, string ftptopath, string filename)
    {
        string retval = string.Empty;
        byte[] filecontents = GetFile(ftpuri, username, password, ftpfrompath, filename);
        retval += SendFile(ftpuri, username, password, ftptopath, filename, filecontents);
        retval += DeleteFile(ftpuri, username, password, ftpfrompath, filename);
        return retval;
    }
    

Ответ 5

В следующем примере кода я попытался использовать следующие данные, и он работает.

Местоположение FTP - "C:\FTP".

Исходное местоположение файла "C:\FTP\Data\FTP.txt".

Файл для перемещения, "C:\FTP\Move\FTP.txt".

Uri serverFile = new Uri("ftp://localhost/Data/FTP.txt");
FtpWebRequest reqFTP= (FtpWebRequest)FtpWebRequest.Create(serverFile);
reqFTP.Method = WebRequestMethods.Ftp.Rename;
reqFTP.Credentials = new NetworkCredential(ftpUser, ftpPass);
reqFTP.RenameTo = "../Move/FTP.txt";

FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();

Ответ 6

У вас есть папки, определенные в службе FTP? Работает ли FTP-сервис? Если ответ на любой вопрос отсутствует, вы не можете использовать FTP для перемещения файлов.

Попробуйте открыть папку FTP в FTP-клиенте и посмотреть, что произойдет. Если у вас все еще есть ошибка, что-то не так с вашим определением, поскольку служба FTP не видит папку, или папка не является логически там, где вы думаете, что она находится в службе FTP.

Вы также можете открыть диспетчер IIS и посмотреть, как все настроено на FTP.

Как и в других способах перемещения файлов, вы можете легко перейти от UNC-пути к другому, если у учетной записи, с которой работает программа, есть соответствующие разрешения для обоих. Путь UNC похож на HTTP или FTP-путь, с ударами в противоположном направлении и не указанным протоколом.

Ответ 7

Код выглядит правильно. Таким образом, либо у вас есть неправильный путь, файл DOESNT существует, либо вам нужно уважать дело (очевидно, что Windows не чувствительна к регистру, но Linux, Unix).

Вы пытались открыть файл в браузере? Откройте Windows File Explorer и введите адрес на панели путей и посмотрите, что вы получаете.

Ответ 8

Я работаю над идентичным типом проекта, попробуйте создать веб-службу, которая может перемещать файлы и запускаться на сервере, где находятся ваши файлы. Постройте его с параметром для передачи имени файла. Когда вы начинаете писать файл, вы можете добавить значение к имени файла, скажем, PK данных, которые коррелируют с файлом и т.д.