How can I use FTP to move files between directories?
Asked Answered
I

9

23

I have a program that needs to move a file from one directory to another on an FTP server. For example, the file is in:

ftp://1.1.1.1/MAIN/Dir1

and I need to move the file to:

ftp://1.1.1.1/MAIN/Dir2

I found a couple of articles recommending use of the Rename command, so I tried the following:

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

But this doesn’t seem to work – I get the following error:

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

At first I thought this might relate to permissions, but as far as I can see, I have permissions to the entire FTP site (it is on my local PC and the uri is resolved to localhost).

Should it be possible to move files between directories like this, and if not, how is it possible?

To address some of the point / suggestions that have been raised:

  1. I can download the same file from the source directory, so it definitely exists (what I'm doing is downloading the file first, and then moving it somewhere else).
  2. I can access the ftp site from a browser (both the source and target directory)
  3. The ftp server is running under my own IIS instance on my local machine.
  4. The path and case are correct and there are no special characters.

Additionally, I have tried setting the directory path to be:

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

Both for the source and target path - but this makes no difference either.

I found this article, which seems to say that specifying the destination as a relative path would help - it doesn't appear to be possible to specify an absolute path as the destination.

reqFTP.RenameTo = “../Dir2/MyFile.txt";
Infield answered 1/2, 2011 at 16:8 Comment(5)
If you plug 1.1.1.1/MAIN/Dir1/MyFile.txt into a browser does it work?Virescent
Does the path contain any special characters that need to be escaped?Platinic
See latest edits, but the answers are: yes - it does work from a browser and, no - the path has no special charactersInfield
@PaulMichaels how was this solved? Just by using .Rename method? :DLaevogyrate
@Roxy'Pro - I'm afraid my memory isn't that good. Given that I marked vlad's answer as correct, I imagine that at least led me to the solution.Infield
F
15

MSDN seems to suggest that your path is considered relative, and therefore it tries to log in to the FTP server using the supplied credentials, then sets the current directory to the <UserLoginDirectory>/path directory. If this isn't the same directory where your file is, you'll get a 550 error.

Fluoroscope answered 1/2, 2011 at 16:19 Comment(6)
See latest edits. I tried various combination of %2f in the path but without successInfield
I updated the question - it looks like you were right, but I didn't manage to get an absolute path to work no matter what I tried.Infield
good find. It would have probably taken me a while to figure this one out if it were my issue.Electrocardiograph
I only knew about it because I browsed those same pages (FTPWebRequest etc) a lot for something I was creatingFluoroscope
I need a similar functionality. However, the destination ftp location has different credentials and source has different credentials. Can someone please suggest how best I can proceed?Intervenient
Relative path can see here : #30900071Electrolier
A
19

Had the same problem and found another way to solve the problem:

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; 

    }
Admit answered 13/9, 2011 at 10:28 Comment(0)
F
15

MSDN seems to suggest that your path is considered relative, and therefore it tries to log in to the FTP server using the supplied credentials, then sets the current directory to the <UserLoginDirectory>/path directory. If this isn't the same directory where your file is, you'll get a 550 error.

Fluoroscope answered 1/2, 2011 at 16:19 Comment(6)
See latest edits. I tried various combination of %2f in the path but without successInfield
I updated the question - it looks like you were right, but I didn't manage to get an absolute path to work no matter what I tried.Infield
good find. It would have probably taken me a while to figure this one out if it were my issue.Electrocardiograph
I only knew about it because I browsed those same pages (FTPWebRequest etc) a lot for something I was creatingFluoroscope
I need a similar functionality. However, the destination ftp location has different credentials and source has different credentials. Can someone please suggest how best I can proceed?Intervenient
Relative path can see here : #30900071Electrolier
B
3

In the following code example I tried with the following data and it works.

FTP Login location is C:\FTP.

File original location C:\FTP\Data\FTP.txt.

File to be moved, 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();
Bernadette answered 3/3, 2016 at 7:34 Comment(0)
E
1

What if you only have absolute paths?

Ok, I came across this post because I was getting the same error. The answer seems to be to use a relative path, which is not very good as a solution to my issue, because I get the folder paths as absolute path strings.

The solutions I've come up with on the fly work but are ugly to say the least. I'll make this a community wiki answer, and if anyone has a better solution, feel free to edit this.

Since I've learned this I have 2 solutions.

  1. Take the absolute path from the move to path, and convert it to a relative 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();
    }
    

or...

  1. Download the file from the "ftp from" path, upload it to the "ftp to" path and delete it from the "ftp from" path.

    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;
    }
    
Esplanade answered 1/2, 2011 at 16:8 Comment(0)
L
1

I was able to get this working but only by using the path as it exists on the server, ie /DRIVELETTER:/FOLDERNAME/filename in RenameTo = "

Luminosity answered 11/4, 2011 at 16:47 Comment(0)
C
0

Do you have those folders defined in the FTP service? Is the FTP service running? If the answer to either question is no, you cannot use FTP to move the files.

Try opening the FTP folder in an FTP client and see what happens. If you still have an error, there is something wrong with your definition as the FTP service does not see the folder or the folder is not logically where you think it is in the FTP service.

You can also open up the IIS manager and look at how things are set up in FTP.

As for other methods to move files, you can easily move from a UNC path to another, as long as the account the program runs under has proper permissions to both. The UNC path is similar to an HTTP or FTP path, with whacks in the opposite direction and no protocol specified.

Caren answered 1/2, 2011 at 16:15 Comment(0)
E
0

The code looks correct. So either you have the wrong path, the file DOESNT exist or you need to respect case (obviously Windows is not case sensitive, but Linux, Unix are).

Did you try to open the file in a browser? Open Windows File Explorer and type the address in the path bar and see what you get.

Electrocardiograph answered 1/2, 2011 at 16:19 Comment(0)
F
-1

U can use this code:

File original location "ftp://example.com/directory1/Somefile.file".

File to be moved, "/newDirectory/Somefile.file".

Note that destination Url not need start with: ftp://example.com

NetworkCredential User = new NetworkCredential("UserName", "password");
FtpWebRequest Wr =FtpWebRequest)FtpWebRequest.Create("ftp://Somwhere.com/somedirectory/Somefile.file");
Wr.UseBinary = true;
Wr.Method = WebRequestMethods.Ftp.Rename;
Wr.Credentials = User;
Wr.RenameTo = "/someotherDirectory/Somefile.file";
back = (FtpWebResponse)Wr.GetResponse();
bool Success = back.StatusCode == FtpStatusCode.CommandOK || back.StatusCode == FtpStatusCode.FileActionOK;
Fruma answered 4/9, 2018 at 11:18 Comment(0)
E
-2

I am working on the identical type of project, try building a web service that can move the files around and runs on the server where your files are. Build it with a parameter to pass in the file name. When writing the file to begin with you might want to append a value to the file name, say the PK of the data that correlates to the file etc.

Expostulation answered 7/2, 2012 at 19:46 Comment(2)
This should be a comment, not an answer.Cervantes
@Jester610, Can you please explain with example.Bernadette

© 2022 - 2024 — McMap. All rights reserved.