I am doing the following very basic task in SSH.NET/C# to download a file from a remote server to a local path:
ConnectionInfo c = new PasswordConnectionInfo(remoteIP, port, username, password);
var sftp = new SftpClient(c);
sftp.Connect();
using (var stream = new FileStream(destinationFile, FileMode.Create))
{
//download the file to our local path
sftp.DownloadFile(fileName, stream);
stream.Close();
}
sftp.Disconnect();
Now to determine if the file completely downloaded successfully, would that just be if the code block reached stream.Close()? Or is there a more concrete way to determine if everything was written okay?
EDIT: This post could be helpful to some if you want to see how many bytes have been downloaded. It also makes a primitive progress bar, which is convenient. I tested the code in the post and it does work.
Looking at the source code for SSH.NET, DownloadFile() is a blocking operation and will not return until the file is written fully.
Additionally, calling stream.Close() inside of the using block is not needed, as the object will be Disposed when exiting the block.
When I was working with SSH.NET a while back, for some reason I didn't know about or didn't like the fact that .DownloadFile had no return value. Either way, this was the route I took at the time.
StringBuilder sb = new StringBuilder();
ConnectionInfo c = new PasswordConnectionInfo(remoteIP, port, username, password);
var sftp = new SftpClient(c);
try
{
using (StreamReader reader = sftp.OpenText(fileName))
{
string line;
while ((line = reader.ReadLine()) != null)
{
sb.AppendLine(line);
}
}
File.WriteAllText(destinationFile, sb.ToString());
}
catch(Exception ex)
{
// procress exception
}
Related
I am currently writing a .csv to client browser using Response object, which was/is a fairly easy job.
But now the requirement has been changed to create this file at a network location from where any time the job will pick it.
I am not sure how can I achieve this, any suggestions would be helpful.
Existing Code:
Response.ClearContent();
Response.AddHeader("content-disposition", "attachment;filename=" + GenerateFileName(publishToViewModel[0].ProjectId));
Response.ContentType = "text/csv";
StreamWriter writer = new StreamWriter();
try
{
string CSVFriendlyData = this.GetCSV(publishToViewModel);
writer.Write(CSVFriendlyData);
Response.Write(writer.ToString());
Response.End();
}
since it is hard to guarantee that a write to a network file will be successful (your old file might still be there, and the timed job might have a lock on it, etc) it's a good idea to build a mechanism that will retry writing to the file several times.
void WriteToNetworkFile()
{
int retries = 3;
while(retries > 0)
{
if(tryWriteFile())
{
break;
}
retries--;
// you could add a timeout here to make sure your attempts are a little more
//spaced out.
//it could be in the form of a Thread.Sleep, or you could extract a method and
//call it using a timer.
if(retries < 1)
{
//log that we failed to write the file and gave up on trying.
}
}
}
protected void tryWriteFile()
{
try
{
//you could pass this path as a parameter too.
var fileLoc = "\\server\folder\file.ext";
//open and obtain read/write lock on the file
//using FileMode.CreateNew will ensure that a new file is created.
//alternatively, you can use FileMosw.Create to create a new file
//or overwrite the old file if it is there.
using (var fs = File.Open(fileLoc, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None))
{
var sw = new StreamWriter(fs);
sw.Write("file contents go here");
sw.Flush();
sw.Close();
return true;
}
}
catch(Exception e)
{
//you might want to log why the write failed here.
return false;
}
}
I am using a web service that returns me some data. I am writing that data in a text file. my problem is that I am having a file already specified in the c# code, where I want to open a dialog box which ask user to save file in his desired location. Here I am posting code which I have used. Please help me in modifying my code. Actually after searching from internet, all are having different views and there is lot of changes in code required where as I do not want to change my code in extent. I am able to write the content in test file but how can I ask user to enter his desire location on computer?
StreamWriter file = new StreamWriter("D:\\test.txt");
HttpWebRequest webreq = (HttpWebRequest)WebRequest.Create(yahooURL);
// Get the response from the Internet resource.
HttpWebResponse webresp = (HttpWebResponse)webreq.GetResponse();
// Read the body of the response from the server.
StreamReader strm =
new StreamReader(webresp.GetResponseStream(), Encoding.ASCII);
string content = "";
for (int i = 0; i < symbols.Length; i++)
{
// Loop through each line from the stream,
// building the return XML Document string
if (symbols[i].Trim() == "")
continue;
content = strm.ReadLine().Replace("\"", "");
string[] contents = content.ToString().Split(',');
foreach (string dataToWrite in contents)
{
file.WriteLine(dataToWrite);
}
}
file.Close();
Try this
using (WebClient Client = new WebClient ())
{
Client.DownloadFile("http://www.abc.com/file/song/a.mpeg", "a.mpeg");
}
I am facing a strange issue, I want to download a list of files from FTP. I preferred to go with Parallel Task. Below is my code. The issue is, all the list of files are getting downloaded, but duplicate files with different name are being generated. I am very new to Parallel task concept. Please help me to find out the issue.
Note: I am using SSH.Net for sftp connection and download.
private void ConcurrentDownload()
{
// Declaring Connection Information
PasswordAuthenticationMethod pm = new PasswordAuthenticationMethod("FTPUserName", "Password");
ConnectionInfo connectionInfo = new ConnectionInfo("FTPHost", 22, "FTPUserName", ProxyTypes.Socks5, "127.0.0.1", 8080, string.Empty, string.Empty, pm);
using (SftpClient sfc = new SftpClient(connectionInfo))
{
// Establish the remote connection
sfc.Connect();
// Getting Remote Directory Contents
IEnumerable<SftpFile> sFiles = new List<SftpFile>();
sFiles = sfc.ListDirectory(".\\");
// Building the File List
List<string> remotefiles = new List<string>();
foreach (SftpFile sfile in sFiles)
{
if (!sfile.IsDirectory)
{
string ss = sfile.Name;
remotefiles.Add(ss);
}
}
// Parallel Download
Parallel.ForEach(remotefiles.Distinct(), file => DownloadFile(sfc, file));
sfc.Disconnect();
}
}
private void DownloadFile(SftpClient sf, string RemoteFileName)
{
using (Stream ms = File.OpenWrite(RemoteFileName))
{
sf.DownloadFile(RemoteFileName, ms);
}
}
You better use Distinct like below
Parallel.ForEach(remotefiles.Distinct(), file => DownloadFile(sfc, file));
if you have duplicate file names and when parallel processing start on same file you will get exception on those duplicate files.
And also you are not downloading to another location, what you are doing is download to same ftp source location. is that correct?
I would give diferent download directory and get file name from source file and then download to that location as below
private void DownloadFile(SftpClient sf, string RemoteFileName)
{
string downloadTo = Path.Combine(DownloadDirectoryPath, Path.GetFileName(RemoteFileName));
using (Stream ms = File.OpenWrite(downloadTo))
{
sf.DownloadFile(RemoteFileName, ms);
}
}
Related Reference : SFTP Async Upload in Parallel
I have a C# program and it will not write to a file but does write to console, even though the file write line is before console. i have tried several modifications and run through debug as well, and it never writes to the file or it puts one line in the file only
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader("urltest.txt");
string myFileName = String.Format("{0}_{1}", DateTime.Now.ToString("yyyyMMddhh"), "-urlcheck.log");
while((line = file.ReadLine()) != null)
{
Uri myUri = new Uri(line);
using (StreamWriter writer = new StreamWriter(myFileName))
try
{
// create the web request and response based on the url that has been
// just read from the file urltest.txt
HttpWebRequest reqFP = (HttpWebRequest)HttpWebRequest.Create(myUri);
HttpWebResponse rspFP = (HttpWebResponse)reqFP.GetResponse();
if (HttpStatusCode.OK == rspFP.StatusCode)
{
// HTTP = 200 - Internet connection available, server online
// Write status of the URL to the log file
writer.WriteLine("================================================================= =========");
writer.WriteLine("Status code of returned: OK " + myUri + " THIS URL IS NOT BLOCKED!");
Console.WriteLine("Status code of returned: OK " + myUri + " THIS URL IS NOT BLOCKED!");
var _uri = myUri.ToString();
string _catstr1 = catURL(_uri);
//regex to get the last 8-9 items of the line and replace them
Regex pat = new Regex(#"</(.*?)a");
string _catstr = pat.Replace(_catstr1, "\x20");
// Write the Catagory of the URL to file and continue
writer.WriteLine("URL " + _catstr);
Console.WriteLine("URL " + _catstr);
}
}
Most anything that writes out to a file should be either within a using block or manually fushed and closed.
using (var writer = ...)
{
// Do your writing
} // <- upon leaving the using block writer will automatically be cleaned up.
Note: I'm not a huge fan of var but as I don't know what class you're using it at least makes a valid example of code
You didn't provide the code for File access, but 99% sure that you didn't close the stream.
call Flush() if you want to force output before you close your writer
I am downloading a file from an ftp server and saving it to the directory defined in Path.GetTempPath(); however, I'm getting the following error: Could not find a part of the path.
I've confirmed that the path returned is correct: C:\Users\[username]\AppData\Local\Temp.
SYSTEM, Administrators, and [username] all have full control over that directory. I thought the point of the temp directory was that it was open for anything/everyone to save to, but just in case, I gave NETWORK SERVICE Modify permissions as well. (I assume that's the username ASP.NET Dev server uses, but I'm not sure.)
I'm using VS 08 on Vista.
Here's my code:
FtpWebRequest downloadRequest = (FtpWebRequest)WebRequest.Create(
ConfigurationManager.AppSettings["FTPServer"] + "//" + fileName);
downloadRequest.Credentials = new NetworkCredential(
ConfigurationManager.AppSettings["FTPUsername"],
ConfigurationManager.AppSettings["FTPPassword"]);
downloadRequest.Method = WebRequestMethods.Ftp.DownloadFile;
FtpWebResponse downloadResponse =
(FtpWebResponse)downloadRequest.GetResponse();
try
{
Stream downloadStream = downloadResponse.GetResponseStream();
if (downloadStream != null)
{
logger.Info("File Download status: {0}",
downloadResponse.StatusDescription);
StreamReader downloadReader = new StreamReader(downloadStream);
try
{
if (downloadReader != null)
{
StreamWriter downloadWriter =
new StreamWriter(Path.GetTempPath());
downloadWriter.AutoFlush = true;
downloadWriter.Write(downloadReader.ReadToEnd());
}
}
finally
{
if (downloadReader != null)
{
downloadReader.Close();
}
}
}
}
finally
{
if (downloadResponse != null)
{
downloadResponse.Close();
}
}
I'd really appreciate any ideas about what I'm doing wrong here.
Thanks!
Looks to me like you need to add a file name to the end of the temp path. Try this:
StreamWriter downloadWriter =
new StreamWriter(Path.Combine(Path.GetTempPath(), fileName));
StreamWriter downloadWriter =
new StreamWriter(Path.GetTempPath());
You're trying to open the StreamWriter on a directory rather than on a file. If you want a temp filename, use Path.GetTempFileName() instead:
StreamWriter downloadWriter =
new StreamWriter(Path.GetTempFileName());
Either that or do what Skinniest Man said.