I am trying to stream a multiline textbox into a text file on an ftp server. Can someone tell me where I may be going wrong?
private void btnSave_Click(object sender, EventArgs e)
{
UriBuilder b = new UriBuilder();
b.Host = "ftp.myserver.com";
b.UserName = "user";
b.Password = "pass";
b.Port = 21;
b.Path = "/myserver.com/directories/" + selected + ".txt";
b.Scheme = Uri.UriSchemeFtp;
Uri g = b.Uri;
System.Net.FtpWebRequest c = (System.Net.FtpWebRequest)System.Net.FtpWebRequest.Create(g);
c.Method = System.Net.WebRequestMethods.Ftp.DownloadFile;
System.Net.FtpWebResponse d = (System.Net.FtpWebResponse)c.GetResponse();
System.IO.Stream h = d.GetResponseStream;
System.IO.StreamWriter SW = new System.IO.StreamWriter(h);
String[] contents = textBox1.Lines.ToArray();
for (int i = 0; i < contents.Length; i++)
{
SW.WriteLine(contents[i]);
}
h.Close();
SW.Close();
d.Close();
}
The error I am getting is this line:
System.IO.StreamWriter SW = new System.IO.StreamWriter(h);
Stream was not writable.
Any ideas?
The response stream from an FTP site is data from the site to you. You'd need the request stream... but then you wouldn't want a method of DownloadFile - you're not downloading, you're uploading, so you want the UploadFile method.
Additionally:
You're not closing anything if exceptions are thrown: use using blocks for this.
It's a bad idea to do network access like this on the UI thread; the UI thread will block (so the whole UI will hang) while the FTP request is happening. Use a background thread instead.
To upload a file you need to use the FtpWebRequest class.
Quote:
When using an FtpWebRequest object to
upload a file to a server, you must
write the file content to the request
stream obtained by calling the
GetRequestStream method or its
asynchronous counterparts, the
BeginGetRequestStream and
EndGetRequestStream methods. You must
write to the stream and close the
stream before sending the request.
For an example of uploading a file (which you can change to writing stream content as in your example) see here.
Taken from MSDN and slightly modified:
public static bool UploadFileOnServer(string fileName, Uri serverUri)
{
// The URI described by serverUri should use the ftp:// scheme.
// It contains the name of the file on the server.
// Example: ftp://contoso.com/someFile.txt.
// The fileName parameter identifies the file
// to be uploaded to the server.
if (serverUri.Scheme != Uri.UriSchemeFtp)
{
return false;
}
// Get the object used to communicate with the server.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(serverUri);
request.Method = WebRequestMethods.Ftp.UploadFile;
StreamReader sourceStream = new StreamReader(fileName);
byte [] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
sourceStream.Close();
request.ContentLength = fileContents.Length;
// This example assumes the FTP site uses anonymous logon.
request.Credentials = new NetworkCredential ("anonymous","janeDoe#contoso.com");
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileContents, 0, fileContents.Length);
requestStream.Close();
FtpWebResponse response = (FtpWebResponse) request.GetResponse();
Console.WriteLine("Upload status: {0}",response.StatusDescription);
response.Close();
return true;
}
Related
I'm trying to make a program using devexpress that uploads and loads directly without going through a local.
I implemented the upload function, but there is no part to load it.
Use loadDocument provided, but its parameter is fileStream.
It seems that I need to use FtpWebRequest after converting to fileStream. What should I do?
''''
string user = "";
string pwd = "";
FtpWebRequest req = (FtpWebRequest)WebRequest.Create("ftp://blahblah/testExcel2.xlsx");
req.Credentials = new NetworkCredential(user, pwd);
req.UseBinary = false;
req.Method = WebRequestMethods.Ftp.UploadFile;
using (FileStream aa = (FileStream)req.GetRequestStream())
{
spreadsheetControl.LoadDocument(aa, DocumentFormat.Xlsx);
}
''''
Accordingly to this this, SpreadsheetControl LoadDocument method receive any Stream, not only FileStream, so just pass response stream to it:
FtpWebRequest req = (FtpWebRequest)WebRequest.Create("ftp://blahblah/testExcel2.xlsx");
....
var response = req.GetResponse();
using (var responseStream = response.GetStream()) {
spreadsheetControl.LoadDocument(responseStream, DocumentFormat.Xlsx);
}
I'm using the code bellow to upload a zip file to to my ftp server:
string zipPath = #"d:\files\start.zip";
string ftpPath = ("ftp://######/start.zip");
WebRequest request = WebRequest.Create(ftpPath);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential("######", "######");
StreamReader sourceStream = new StreamReader(zipPath);
byte[] fileContents = Encoding.Unicode.GetBytes(sourceStream.ReadToEnd());
sourceStream.Close();
request.ContentLength = fileContents.Length;
try
{
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileContents, 0, fileContents.Length);
requestStream.Close();
FtpWebResponse makeFileUploadResponse = (FtpWebResponse)request.GetResponse();
}
catch
{
MessageBox.Show("ftp failed!");
}
My zip archive is definitely valid (I can open it and extract it) but when I download the uploaded zip file, I got the error that archive is damaged.
Update 1: my source code is from MSDN article:How to: Upload Files with FTP
you should cast request to FtpWebRequest (as in that MSDN example)
and then specify request as binary (you're uploading binary file, not text).
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("aa");
request.Method = WebRequestMethods.Ftp.UploadFile;
request.UseBinary = true;
I can't say what the problem is but I can provide an alternate solution. You can use WebClient instead of WebRequest
string zipPath = #"d:\files\start.zip";
string ftpPath = ("ftp://######/start.zip");
WebClient ftpClient = new WebClient();
ftpClient.Credentials = new NetworkCredential("####", "######");
try{
ftpClient.UploadFile(ftpPath, WebRequestMethods.Ftp.AppendFile, zipPath);
}
catch(WebException ex){
MessageBox.Show("ftp failed");
}
I ve got the following code which
foreach (string dir in dirs) { //dirs all files in directory
try{
// Get an instance of WebClient
WebClient client = new System.Net.WebClient();
// parse the ftp host and file into a uri path for the upload
Uri uri = new Uri(m_FtpHost + new FileInfo(dir).Name);
// set the username and password for the FTP server
client.Credentials = new System.Net.NetworkCredential(m_FtpUsername, m_FtpPassword);
// upload the file asynchronously, non-blocking.
client.UploadFileAsync(uri, "STOR",dir);
}
catch(Exception e){
print(e.Message);
}
}
Can I retrieve back the progress of the upload? I have in the dirs 4-5 files. I want exact the progress (not the files uploaded/(total files))
EDIT: Thus the right approach is the following:
public int percentage;
try{
// Get an instance of WebClient
WebClient client = new System.Net.WebClient();
// parse the ftp host and file into a uri path for the upload
Uri uri = new Uri(m_FtpHost + new FileInfo(dir).Name);
// set the username and password for the FTP server
client.Credentials = new System.Net.NetworkCredential(m_FtpUsername, m_FtpPassword);
// upload the file asynchronously, non-blocking.
client.UploadProgressChanged += WebClientUploadProgressChanged;
client.UploadFileCompleted += WebClientUploadCompleted;
client.UploadFileAsync(uri, "STOR",dir);
}
void WebClientUploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
{
percentage = e.ProgressPercentage;
}
void WebClientUploadCompleted(object sender, UploadFileCompletedEventArgs e)
{
print( "Upload is finished. ");
}
I add this implementation to my code, however it seems that it doenst print anything in the console.
WebClient contains a dedicated event for this
public event UploadProgressChangedEventHandler UploadProgressChanged
https://msdn.microsoft.com/en-us/library/system.net.webclient.uploadprogresschanged(v=vs.110).aspx
EDIT : HttpWebRequest approach based on a google result :
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "text/plain";
request.Timeout = -1; //Infinite wait for the response.
// Get the file information object.
FileInfo fileInfo = new FileInfo("C:\\Test\\uploadFile.dat");
// Set the file content length.
request.ContentLength = fileInfo.Length;
// Get the number of segments the file will be uploaded to the stream.
int segments = Convert.ToInt32(fileInfo.Length / (1024 * 4));
// Get the source file stream.
using (FileStream fileStream = fileInfo.OpenRead())
{
// Create 4KB buffer which is file page size.
byte[] tempBuffer = new byte[1024 * 4];
int bytesRead = 0;
// Write the source data to the network stream.
using (Stream requestStream = request.GetRequestStream())
{
// Loop till the file content is read completely.
while ((bytesRead = fileStream.Read(tempBuffer, 0, tempBuffer.Length)) > 0)
{
// Write the 4 KB data in the buffer to the network stream.
requestStream.Write(tempBuffer, 0, bytesRead);
// Update your progress bar here using segment count.
}
}
}
// Post the request and Get the response from the server.
using (WebResponse response = request.GetResponse())
{
// Request is successfully posted to the server.
}
I need some help reworking this Method in such a way that it will not create a new FTP session for every file that is uploaded.
The variables are
server (IP or Hostname)
Dictionary(local file path, ftp server path) ex (c:/mydir/test.txt, \incoming)
PASV Use Passive Mode True/False
and the login/password to the FTP itself
I would like this to work in such a way.
1) Connect to server
2) For each file/path pair in dictionary, upload file
3) Disconnect from server
Is it possible to rewrite this method to accomplish that?
Also I know the try/catch should be better implemented, I'd like to have a try/catch block for login to the FTP itself, then a try block for each file uploaded but I need to sort out the structure of the method first.
protected static bool FtpStart(string server, Dictionary<string, string> FilePath, bool PASV, string login, string password)
{
foreach (var Current in FilePath)
{
try
{
//FileInfo for Filename passed.
var ThisFile = new FileInfo(Current.Key);
// Get the object used to communicate with the server.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://" + server + Current.Value + ThisFile.Name);
request.UsePassive = PASV;
request.Method = WebRequestMethods.Ftp.UploadFile;
// This example assumes the FTP site uses anonymous logon.
request.Credentials = new NetworkCredential(login, password);
// Copy the contents of the file to the request stream.
StreamReader sourceStream = new StreamReader(Current.Key);
byte[] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
sourceStream.Close();
request.ContentLength = fileContents.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileContents, 0, fileContents.Length);
requestStream.Close();
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
response.Close();
}
catch (Exception Ex)
{
Console.WriteLine(Ex.Message);
return false;
}
}
return true;
}
You can KeepAlive your request to avoid connection closing
request.KeepAlive = true;
This will make a login only the first FTPWebRequest.
Then when you create the last FTPWebRequest
request.KeepAlive = false;
and it will close the connection when done.
I am trying to transfer files between a couple of sites and I'm using FtpWebRequest to download the file from site A and upload it to site B.
The problem I'm facing is when I am downloading the file I'm not getting more then 8820 bytes of data.
Heres the code I am using:
public FtpFile Download(string path)
{
string fullpath = ConstructFullpath(path);
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(fullpath);
request.Method = WebRequestMethods.Ftp.DownloadFile;
// login
request.Credentials = new NetworkCredential(Username, Password);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = request.GetResponse().GetResponseStream();
byte[] data = new byte[20000];
int length = responseStream.Read(data, 0, data.Length);
responseStream.Close();
FtpFile file = new FtpFile(path, data, length);
return file;
}
public bool Upload(FtpFile file)
{
if (!DirectoryExists(GetDirectory(file.Path)))
{
CreateDirectory(GetDirectory(file.Path));
}
string fullpath = ConstructFullpath(file.Path);
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(fullpath);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(Username, Password);
Stream stream = request.GetRequestStream();
stream.Write(file.Data, 0, file.Length);
stream.Close();
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
return true;
}
The First image shows the source directory.
The second image shows the destination directory.
I have tried saving the files locally and have the same result.
You're only calling Read once:
byte[] data = new byte[20000];
int length = responseStream.Read(data, 0, data.Length);
responseStream.Close();
There's no guarantee that all the data will be read in a single call, and you should never rely on it doing so. You should loop round (e.g. copying the data into a MemoryStream) until Read returns 0.
If you're using .NET 4, Stream.CopyTo makes this easy:
MemoryStream ms = new MemoryStream();
responseStream.CopyTo(ms);
Note that you should also use using statements instead of closing resources explicitly, and that includes the FtpWebResponse.