FtpWebRequest - Transferring file name containing fragment marker (#) - c#

EDIT: Not sure its the answer but it is a workaround... rather than looking at the file transfer objects I added .Replace to the FTP string and got the result I was looking for, the target file name is now matching the source file name.
FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create("ftp://" + targetServer + targetPath + fileInfo.Name.Replace("#", "%23"));
I have an existing C# FTP process that has been in use for years. A new file naming convention was implemented that uses the # character in the actual file name. From what I can tell the # is being interpreted as a fragment marker during the file transfer resulting in an incorrect file name on the target server.
Source file name: '9300T_#Test.xml'
Target file name: '9300T_'
Is there a way to force the actual file name to be used?
When I view object values during execution I can see the original string is correct but I also see the '#Test.xml' under the Fragment property.
I've experimented with different properties of WebRequest, FtpWebRequest, and Uri. So far I have not found a combination that works and have not found a solution on the web.
I've tested using other FTP clients (DOS prompt, Mozilla) and the file is transferred correctly which leads me to believe the solution is property driven, or, it is a limitation to the objects I'm using.
Below is the code I'm testing from a windows form which produces the problem.
Thanks.
string sourcePath = #"C:\FILES\";
string sourcePattern = "9300T*.xml";
string targetServer = "test_server_name";
string targetPath = "/";
string targetLogin = "server_login";
string targetPassword = "login_password";
string[] uploadFiles = Directory.GetFiles(sourcePath, sourcePattern);
// Loop through and process the list.
foreach (string file in uploadFiles)
{
// Create the file information object.
FileInfo fileInfo = new FileInfo(file);
// Create the FTP request object.
FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create("ftp://" + targetServer + targetPath + fileInfo.Name);
ftpRequest.Credentials = new NetworkCredential(targetLogin, targetPassword);
ftpRequest.KeepAlive = false;
ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = true;
ftpRequest.ContentLength = fileInfo.Length;
// Opens a file stream to read the file being uploaded.
FileStream readStream = fileInfo.OpenRead();
// Create the stream to which the upload file is written to.
Stream writeStream = ftpRequest.GetRequestStream(); // -- TARGET FILE IS CREATED WITH WRONG NAME AT THIS POINT
// Set the buffer size.
int bufferLength = 2048;
byte[] buffer = new byte[bufferLength];
// Read from and write to streams until content ends.
int contentLength = readStream.Read(buffer, 0, bufferLength);
while (contentLength != 0)
{
writeStream.Write(buffer, 0, contentLength);
contentLength = readStream.Read(buffer, 0, bufferLength);
}
// Flush and close the streams.
readStream.Flush();
readStream.Close();
writeStream.Flush();
writeStream.Close();
fileInfo.Delete();
}

When you are concatenating file name to create URL for web request,
you have to escape file name using percent-enconding, otherwise characters after "#" are considered to be URL fragment instead of being part of the file name.
I suggest to use function like Uri.EscapeDataString() Instead of Replace("#", "%23"), because it properly handles all other reserved characters (such as '#').
FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create("ftp://" + targetServer + targetPath + Uri.EscapeDataString(fileInfo.Name));
If targetPath could contain reserved characters, you may need to escape it too.

Related

I'm getting "The process cannot access the file because it is being used by another process" error. Any ideas?

So, I created a file and a txt file into the AppData, and I want to overwrite the txt. But when I try to do it, it keeps giving me that error. Any ideas?
string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string setuppath = (path + "\\");
string nsetuppath = (setuppath + "newx" + "\\");
Directory.CreateDirectory(nsetuppath);
string hedef2 = (nsetuppath + "commands.txt");
File.Create(hedef2);
StreamWriter sw = new StreamWriter(hedef2); ----> This is where the error appears.
sw.WriteLine("Testtest");
Just use the using statement when using streams. The using statement automatically calls Dispose on the object when the code that is using it has completed.
//path to the file you want to create
string path = #"C:\code\Test.txt";
// Create the file, or overwrite if the file exists.
using (FileStream fs = File.Create(path))
{
byte[] info = new UTF8Encoding(true).GetBytes("This is some text in the file.");
// Add some information to the file.
fs.Write(info, 0, info.Length);
}
There are many ways of manipulate streams, keep it simple depending on your needs

C# Download File from a network drive

I have a file that is located at a network drive. The user access is already created to have full access to the path. But it seems that when I ran the following code to get the file, the browser just does not respond.
FileInfo file = new FileInfo(GetDocumentUploadFolder(ID) + fileName);
// Checking if file exists
if (file.Exists)
{
// Clear the content of the response
this.Page.Response.ClearContent();
// Clear the header of the response
this.Page.Response.ClearHeaders();
// Set the ContentType
this.Page.Response.ContentType = "application/pdf";
// Write the file into the response (TransmitFile is for ASP.NET 2.0. In ASP.NET 1.1 you have to use WriteFile instead)
this.Page.Response.WriteFile(file.FullName);
// End the response
this.Page.Response.End();
}
I tried using this.Page.Response.TransmitFile(file.FullName); and it also does not work. The page seems to stop functioning after this.Page.Response.End();
Any ideas?
No matter where file a stored. Your action must return a file as the result:
public FileResult GetBytes()
{
string path = Server.MapPath("~/Files/PDFIcon.pdf");
byte[] mas = System.IO.File.ReadAllBytes(path);
string file_type = "application/pdf";
string file_name = "PDFIcon.pdf";
return File(mas, file_type, file_name);
}
Server.MapPath(filePath string) - must have access to the file.
I am able to do a workaround by copying the files first from the network drive to local path and then do a TransmitFile from there:
FileInfo file = new FileInfo(GetDocumentUploadFolder(ID) + fileName);
string strFolder = Server.MapPath(LocalLocation);
string strDestination = Server.MapPath(LocalLocation + "\\" + fileName);
// Checking if file exists
if (file.Exists)
{
if (!Directory.Exists(strFolder))
Directory.CreateDirectory(strFolder);
// Delete contents in this folder
Common.DeleteFiles(strFolder, "*.*");
file.CopyTo(strDestination, true);
// Clear the content of the response
this.Page.Response.ClearContent();
// Clear the header of the response
this.Page.Response.ClearHeaders();
// Set the ContentType
this.Page.Response.ContentType = "application/pdf";
// Write the file into the response (TransmitFile is for ASP.NET 2.0. In ASP.NET 1.1 you have to use WriteFile instead)
this.Page.Response.TransmitFile(strDestination);
// End the response
this.Page.Response.End();
}

CSV Filename not found when Space or (%20) exists in FileName

I am trying to read a CSV file to upload it to a database Table using the following code:
FtpWebRequest reqFTP;
try
{
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpPath + fileName));
reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
reqFTP.UseBinary = true;
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
int count=0;
StringBuilder sb = new StringBuilder();
//GET THE FTP RESPONSE
using (System.Net.WebResponse tmpRes = reqFTP.GetResponse())
//^^^^^^^^^^^^^^ Error is on this line ^^^^^^^^^^^^^^
{
...
}
}
When the file name contains a space (which sometimes shows as %20 while debugging) i get the following error:
The remote server returned an error: (550) File unavailable (e.g., file not >found, no access).
If the filename does not contain a space or %20 it gets read fine.
The task involves to read the file parse contents save data in database and then move file in another folder.
Whenever you are gathering or setting your filenames, try this:
if (filename.Contains(" "))
{
filename= filename.Replace(" ", Uri.HexEscape(' '));
}
If you plan to move the file afterwards, make sure you go thru and do the opposite before the move. In your case:
if (filename.Contains("%20"))
{
filename= filename.Replace("%20", ' ');
}
This idea can be expand for all unacceptable characters like "#", or "'", or "\" and so forth.

Writing binary data to ftp location

How come this code writes an empty file at given location?
No error messages.
// upload file
WebRequest upload = WebRequest.Create(ftp + path + "/" + file);
upload.Method = WebRequestMethods.Ftp.UploadFile;
upload.Credentials = new NetworkCredential(username, password);
String filePath = HttpContext.Current.Server.MapPath("~/temp/" + file); // path to file to upload
Stream myReadStream = new FileStream(filePath, FileMode.Create); // stream that can read binary data
BinaryWriter myStreamWriter = new BinaryWriter(upload.GetRequestStream()); // writer that can write the binary data to the FTP server
while (myReadStream.ReadByte() != -1)
{
myStreamWriter.Write(myReadStream.ReadByte());
}
myStreamWriter.Close();
myReadStream.Close();
Removing the while loop creates a file 4byte big and corrupt so I guess I cant get in the while loop like this.
You should call upload.GetResponse() after myStreamWriter closed.
PS: In the while you write ONE time for every TWO times read, is it really you want?

WCF Service sends a .txt or .xls but not a .gz (Zipped file)

I have a WCF service up and running which saves a file to my server. I have tested this by sending a .txt file and a .xls file. The size of the .xls file is 90kb.
Now I have a zipped file .gz that is only 70KB in size but when trying to complete this operation I get
The remote server returned an unexpected response: (400)
Bad Request.
When I have tried to search for this Bad Request most results lead to the fact that a large file is being sent and that I need to change the settings in the config file.
This is not the reason in my case as the .gz file is smaller than the .xls file!
Does anyone have any idea why this type of file cannot be sent the same as a text or Excel file???
Edit: Code Added
Here is the method to call the service
string name = "New Doc";
string file = #"C:/Users/Admin/Desktop/fileZipped.gz";
string ext = file.Split('.')[1];
Stream stream = File.OpenRead(file);
byte[] bytes = new byte[stream.Length];
stream.Read(bytes, 0, (int)stream.Length);
stream.Close();
var uploadFileServiceClient = new UploadFileServiceClient();
uploadFileServiceClient.UploadFile(name, bytes, ext);
And here is my service:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class UploadFileService : IUploadFileService
{
public bool UploadFile(string name, byte[] bytes, string extension)
{
string importDir = ConfigurationSettings.AppSettings["UploadFileDir"];
if (String.IsNullOrEmpty(importDir))
return false;
if (!Directory.Exists(importDir))
return false;
string outputFile = Path.Combine(importDir, Guid.NewGuid() + "." + extension);
string filename = outputFile.Split('\\')[2];
using (StreamWriter sw = new StreamWriter(outputFile))
{
sw.WriteLine(bytes);
sw.Flush();
sw.Close();
}
return true;
}
}
Like I say it works for text or Excel files.
IF there is no "filtering proxy" inbetween:
We had something similar and the solution turned out to setup the MIME type on client+server accordingly...

Categories

Resources