2011-02-01 41 views
16

Tengo un programa que necesita mover un archivo de un directorio a otro en un servidor FTP. Por ejemplo, el archivo está en:¿Cómo puedo usar FTP para mover archivos entre directorios?

ftp://1.1.1.1/MAIN/Dir1 

y tengo que mover el archivo a:

ftp://1.1.1.1/MAIN/Dir2 

me encontré con un par de artículos que recomiendan el uso del comando Cambiar nombre, por lo que trató lo siguiente:

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

Pero esto no parece funcionar - me sale el siguiente error:

The remote server returned an error: (550) File unavailable (e.g., file not found, no access).

Al principio pensé que esto podría estar relacionado con los permisos, pero por lo que puedo ver, tengo permisos para todo el sitio FTP (está en mi PC local y el uri se resuelve en localhost).

¿Debería ser posible mover archivos entre directorios como este, y si no es así, cómo es posible?

Para hacer frente a algunos de los puntos y/o sugerencias que se han planteado:

  1. puedo descargar el mismo archivo desde el directorio de origen, por lo que definitivamente existe (lo que estoy haciendo es descargar el archivo en primer lugar, y luego moverlo a otro lugar).
  2. Puedo acceder al sitio ftp desde un navegador (tanto el directorio de origen como el de destino)
  3. El servidor ftp se está ejecutando en mi propia instancia de IIS en mi máquina local.
  4. La ruta y el caso son correctos y no hay caracteres especiales.

Además, he intentado fijar la ruta del directorio a ser:

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

Tanto para la ruta de origen y de destino - pero esto no hace ninguna diferencia tampoco.

Encontré this artículo, que parece decir que la especificación del destino como una ruta relativa ayudaría; no parece posible especificar una ruta absoluta como destino.

reqFTP.RenameTo = “../Dir2/MyFile.txt"; 
+1

Si conecta ftp://1.1.1.1/MAIN/Dir1/MyFile.txt en un navegador, ¿funciona? –

+0

¿La ruta contiene algún carácter especial que deba escaparse? –

+0

Ver las últimas ediciones, pero las respuestas son: sí, funciona desde un navegador y, no, la ruta no tiene caracteres especiales –

Respuesta

10

MSDN parece sugerir que su ruta se considera relativa y, por lo tanto, intenta iniciar sesión en el servidor FTP utilizando las credenciales proporcionadas, luego establece el directorio actual en el directorio <UserLoginDirectory>/path. Si este no es el mismo directorio donde está su archivo, obtendrá un error de 550.

+0

Ver las últimas ediciones. Intenté varias combinaciones de% 2f en la ruta, pero sin éxito –

+0

Actualicé la pregunta, parece que tenía razón, pero no logré obtener una ruta de acceso absoluta sin importar lo que intenté. –

+0

buen hallazgo. Probablemente me hubiera llevado un tiempo resolver esto si fuera mi problema. –

0

¿Tiene esas carpetas definidas en el servicio FTP? ¿Se está ejecutando el servicio FTP? Si la respuesta a cualquiera de las preguntas es no, no puede usar FTP para mover los archivos.

Intente abrir la carpeta FTP en un cliente FTP y vea qué ocurre. Si aún tiene un error, su definición tiene algún problema, ya que el servicio FTP no ve la carpeta o la carpeta no está lógicamente donde usted cree que está en el servicio FTP.

También puede abrir el administrador de IIS y ver cómo se configuran las cosas en FTP.

En cuanto a otros métodos para mover archivos, puede pasar fácilmente de una ruta UNC a otra, siempre que la cuenta con la que se ejecuta el programa tenga los permisos adecuados para ambas. La ruta UNC es similar a una ruta HTTP o FTP, con golpes en la dirección opuesta y sin protocolo especificado.

0

El código parece correcto. Entonces, o tiene una ruta incorrecta, el archivo NO existe o necesita respetar el caso (obviamente, Windows no distingue entre mayúsculas y minúsculas, pero Linux, Unix sí lo está).

¿Intentaste abrir el archivo en un navegador? Abra Windows File Explorer y escriba la dirección en la barra de ruta y vea lo que obtiene.

+0

Ver las últimas ediciones - el archivo se abre bien en un navegador –

1

que era capaz de conseguir este trabajo, pero sólo mediante el uso de la vía, tal como existe en el servidor, es decir /DRIVELETTER:/FOLDERNAME/filename en renameTo = "

1

Lo que si sólo tiene rutas absolutas?

Ok, yo he venido en esta publicación porque recibía el mismo error. La respuesta parece ser utilizar una ruta relativa, que no es muy buena como solución a mi problema, porque obtengo las rutas de la carpeta como cadenas de ruta absolutas.

Las soluciones que he ideado sobre la marcha funcionan, pero son feas por decir lo menos. Haré de esto una respuesta wiki de la comunidad, y si hay alguna. Si tiene una mejor solución, no dude en editar esto.

Desde que aprendí esto, tengo 2 soluciones.

  1. Tome la ruta absoluta desde el movimiento a la ruta, y conviértala a una URL relativa.

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

o ...

  1. Descargar el archivo del "ftp de" camino, subirlo a la "ftp para" ruta de acceso y eliminarlo de la "ftp desde" camino.

    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; 
    } 
    
16

tenía el mismo problema y encontrar otra manera de resolver el problema:

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; 

    } 
-2

estoy trabajando en el mismo tipo de proyecto, trata de la construcción de un servicio web que puede mover los archivos alrededor y se ejecuta en el servidor donde están sus archivos. Compilarlo con un parámetro para pasar el nombre del archivo. Al escribir el archivo para comenzar, puede agregar un valor al nombre del archivo, por ejemplo, PK de los datos que se correlacionan con el archivo, etc.

+1

Este debería ser un comentario, no una respuesta. –

+0

@ Jester610, ¿Puedes explicar con un ejemplo? –

1

En el siguiente ejemplo de código probé con los datos siguientes y funciona.

FTP La ubicación de inicio de sesión es "C: \ FTP".

Ubicación original del archivo "C: \ FTP \ Data \ FTP.txt".

Archivo que se va a mover, "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(); 
Cuestiones relacionadas