web-dev-qa-db-fra.com

Comment puis-je utiliser FTP pour déplacer des fichiers entre les répertoires?

J'ai un programme qui doit déplacer un fichier d'un répertoire à un autre sur un serveur FTP. Par exemple, le fichier se trouve dans:

ftp://1.1.1.1/MAIN/Dir1

et je dois déplacer le fichier vers:

ftp://1.1.1.1/MAIN/Dir2

J'ai trouvé quelques articles recommandant l'utilisation de la commande Renommer, j'ai donc essayé ce qui suit:

    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();

Mais cela ne semble pas fonctionner - j'obtiens l'erreur suivante:

Le serveur distant a renvoyé une erreur: (550) Fichier indisponible (par exemple, fichier introuvable, pas d'accès).

Au début, je pensais que cela pouvait être lié aux autorisations, mais pour autant que je sache, j'ai des autorisations sur l'ensemble du site FTP (c'est sur mon PC local et l'uri est résolu en localhost).

Devrait-il être possible de déplacer des fichiers entre des répertoires comme celui-ci, et sinon, comment est-ce possible?

Pour répondre à certains des points/suggestions qui ont été soulevés:

  1. Je peux télécharger le même fichier depuis le répertoire source, donc il existe définitivement (ce que je fais, c'est d'abord télécharger le fichier, puis le déplacer ailleurs).
  2. Je peux accéder au site ftp à partir d'un navigateur (à la fois le répertoire source et le répertoire cible)
  3. Le serveur ftp fonctionne sous ma propre instance IIS sur ma machine locale.
  4. Le chemin et la casse sont corrects et il n'y a pas de caractères spéciaux.

De plus, j'ai essayé de définir le chemin du répertoire pour qu'il soit:

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

Tant pour le chemin source que pour le chemin cible - mais cela ne fait aucune différence non plus.

J'ai trouvé cet article, qui semble dire que spécifier la destination comme chemin relatif aiderait - il ne semble pas possible de spécifier un chemin absolu comme destination.

reqFTP.RenameTo = “../Dir2/MyFile.txt";
19
Paul Michaels

[~ # ~] msdn [~ # ~] semble suggérer que votre chemin est considéré comme relatif, et donc il essaie pour vous connecter au serveur FTP à l'aide des informations d'identification fournies, puis définit le répertoire actuel sur <UserLoginDirectory>/path répertoire. Si ce n'est pas le même répertoire où se trouve votre fichier, vous obtiendrez une erreur 550.

13
vlad

A eu le même problème et a trouvé une autre façon de résoudre le problème:

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; 

    }
18
Ruedi

Dans l'exemple de code suivant, j'ai essayé avec les données suivantes et cela fonctionne.

L'emplacement de connexion FTP est "C:\FTP".

Emplacement d'origine du fichier "C:\FTP\Data\FTP.txt".

Fichier à déplacer, "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();
2
Pabitra Dash

Et si vous n'avez que des chemins absolus?

Ok, je suis tombé sur ce post parce que j'obtenais la même erreur. La réponse semble être d'utiliser un chemin relatif, ce qui n'est pas très bon comme solution à mon problème, car j'obtiens les chemins de dossier sous forme de chaînes de chemin absolues.

Les solutions que j'ai trouvées à la volée fonctionnent mais sont laides pour le moins. Je vais en faire une réponse wiki communautaire, et si quelqu'un a une meilleure solution, n'hésitez pas à la modifier.

Depuis que j'ai appris cela, j'ai 2 solutions.

  1. Prenez le chemin absolu du déplacement vers le chemin et convertissez-le en une URL relative.

    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();
    }
    

ou...

  1. Téléchargez le fichier depuis le chemin "ftp from", téléchargez-le dans le chemin "ftp to" et supprimez-le du chemin "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;
    }
    
1
stephenbayer

J'ai pu faire fonctionner cela mais uniquement en utilisant le chemin tel qu'il existe sur le serveur, c'est-à-dire /DRIVELETTER:/FOLDERNAME/filename dans RenameTo = "

1
R Owen

Le code semble correct. Donc, soit vous avez le mauvais chemin, le fichier n'existe pas ou vous devez respecter la casse (Windows n'est évidemment pas sensible à la casse, mais Linux, Unix le sont).

Avez-vous essayé d'ouvrir le fichier dans un navigateur? Ouvrez l'Explorateur de fichiers Windows et tapez l'adresse dans la barre de chemin d'accès et voyez ce que vous obtenez.

0
Dustin Davis

Avez-vous ces dossiers définis dans le service FTP? Le service FTP fonctionne-t-il? Si la réponse à l'une des questions est non, vous ne pouvez pas utiliser FTP pour déplacer les fichiers.

Essayez d'ouvrir le dossier FTP dans un client FTP et voyez ce qui se passe. Si vous avez toujours une erreur, il y a un problème avec votre définition car le service FTP ne voit pas le dossier ou le dossier n'est pas logiquement là où vous pensez qu'il se trouve dans le service FTP.

Vous pouvez également ouvrir le gestionnaire IIS et voir comment les choses sont configurées dans FTP.

Quant aux autres méthodes pour déplacer des fichiers, vous pouvez facilement passer d'un chemin UNC à un autre, tant que le compte sous lequel le programme s'exécute dispose des autorisations appropriées pour les deux. Le chemin UNC est similaire à un chemin HTTP ou FTP, avec des whacks dans la direction opposée et aucun protocole spécifié.

0
Gregory A Beamer