How can I fix the following method? - c#

I made a method which can scan an ftp server. It has two parts in an if...else statement. The first part in the if runs when the list of directories equals to 0, and separate the folders from the files( and put them into that list). Then(because the list is no more empty) the else statement should runs. It has a foreach loop which check all elements of the list and concat them to the ftp address and scan that folder. And here's the problem. Looks like it turn into an infinite loop. I only want to check the folders on the server and break the loop but looks like I cannot find a useful solution.
Here's the code:
internal void ListFilesOnServer()
{
ArrayList files = new ArrayList();
if (directories.Count == 0)
{
try
{
FtpWebRequest ftpwrq = (FtpWebRequest)WebRequest.Create(server);
ftpwrq.Credentials = new NetworkCredential(user, passw);
ftpwrq.Method = WebRequestMethods.Ftp.ListDirectory;
ftpwrq.KeepAlive = false;
FtpWebResponse fresponse = (FtpWebResponse)ftpwrq.GetResponse();
StreamReader sr = new StreamReader(fresponse.GetResponseStream());
string temp = "";
while ((temp = sr.ReadLine()) != null)
{
files.Add(temp);
}
temp = String.Empty;
sr.Close();
fresponse.Close();
DirOrFile(files);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
else
{
foreach (string file in directories.ToArray())
{
try
{
FtpWebRequest ftpwrq = (FtpWebRequest)WebRequest.Create(server+"/"+file);
ftpwrq.Credentials = new NetworkCredential(user, passw);
ftpwrq.Method = WebRequestMethods.Ftp.ListDirectory;
ftpwrq.KeepAlive = false;
FtpWebResponse fresponse = (FtpWebResponse)ftpwrq.GetResponse();
StreamReader sr = new StreamReader(fresponse.GetResponseStream());
string temp = "";
while ((temp = sr.ReadLine()) != null)
{
files.Add(temp);
}
temp = String.Empty;
sr.Close();
fresponse.Close();
DirOrFile(files);
}
catch(ArgumentException)
{
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
}
ListFilesOnServer();
}

The infinite loop is because you don't have a way to break out of the recursion.
The pattern for recursion looks like this
MyRecursiveMethod()
{
if (conditions)
{
}
else
{
MyRecursiveMethod()
}
}
Here's how I might go about rewriting this code to make it work for you.
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Security;
using System.Windows.Forms;
namespace ConsoleApplication5
{
public class FtpTest
{
string server = "servier/";
string user = "user";
SecureString passw = new SecureString();
public List<string> GetFilesOnServer()
{
return GetFilesOnServer(server);
}
public List<string> GetFilesOnServer(string dir)
{
var root = GetDirectoryContents(dir);
var files = new List<string>();
foreach (string name in root)
{
var path = GetFullPath(dir, name);
if (IsDirectory(name))
{
var subFiles = GetFilesOnServer(path);
files.AddRange(subFiles);
}
else
{
files.Add(path);
}
}
return files;
}
public List<string> GetDirectoryContents(string dir)
{
var files = new List<string>();
try
{
var ftpwrq = (FtpWebRequest)WebRequest.Create(dir);
ftpwrq.Credentials = new NetworkCredential(user, passw);
ftpwrq.Method = WebRequestMethods.Ftp.ListDirectory;
ftpwrq.KeepAlive = false;
var fresponse = (FtpWebResponse)ftpwrq.GetResponse();
var sr = new StreamReader(fresponse.GetResponseStream());
string fileName = "";
while ((fileName = sr.ReadLine()) != null)
{
files.Add(fileName);
}
sr.Close();
fresponse.Close();
return files;
}
catch (ArgumentException)
{
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
return files;
}
public static string GetFullPath(string dir, string file)
{
string path = dir;
if (!path.EndsWith("/"))
path += "/";
path += file;
return path;
}
public static bool IsDirectory(string name)
{
return name.IndexOf(".") > 0;
}
}
}
Note that I only recursively call into GetFilesOnServer if the item retrieved is a directory. I've also refactored out the code that grabs the contents on the FTP server into a non-recursive method.
Hope this helps you out.

Related

How do I make it so catch stops looping and goes back to the beginning of the loop

When running this code once it catches an exception it will keep repeating "The file was not found". How do I make it so it goes back to the beginning of the loop instead?
private static List<Party> FindData(string exactpath)
{
bool validInput = false;
while(validInput==false)
{
try
{
// Store values in a list of string
List<string> file = File.ReadAllLines(exactpath).ToList();
List<Party> parties = new List<Party>();
foreach (string line in file.Skip(3))
{
string[] items = line.Split(',');
Party p = new Party(items[0], Convert.ToInt32(items[1]), items.Skip(2).ToArray());
parties.Add(p);
}
return parties;
}
catch (FileNotFoundException)
{
Console.WriteLine($"The file was not found");
}
}
return null;
}
Example when not finding the file:
Break; should do the trick. Is it what you are looking for?
private static List<Party> FindData(string exactpath)
{
bool validInput = false;
while(validInput==false)
{
try
{
// Store values in a list of string
List<string> file = File.ReadAllLines(exactpath).ToList();
List<Party> parties = new List<Party>();
foreach (string line in file.Skip(3))
{
string[] items = line.Split(',');
Party p = new Party(items[0], Convert.ToInt32(items[1]), items.Skip(2).ToArray());
parties.Add(p);
}
return parties;
}
catch (FileNotFoundException)
{
Console.WriteLine($"The file was not found");
break;
}
}
return null;
}

How to create zip file in memory?

I have to create a zip file from set of urls. and it should have a proper folder structure.
So i tried like
public async Task<byte[]> CreateZip(Guid ownerId)
{
try
{
string startPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "zipFolder");//base folder
if (Directory.Exists(startPath))
{
DeleteAllFiles(startPath);
Directory.Delete(startPath);
}
Directory.CreateDirectory(startPath);
string zipPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{ownerId.ToString()}"); //folder based on ownerid
if (Directory.Exists(zipPath))
{
DeleteAllFiles(zipPath);
Directory.Delete(zipPath);
}
Directory.CreateDirectory(zipPath);
var attachemnts = await ReadByOwnerId(ownerId);
attachemnts.Data.ForEach(i =>
{
var fileLocalPath = $"{startPath}\\{i.Category}";
if (!Directory.Exists(fileLocalPath))
{
Directory.CreateDirectory(fileLocalPath);
}
using (var client = new WebClient())
{
client.DownloadFile(i.Url, $"{fileLocalPath}//{i.Flags ?? ""}_{i.FileName}");
}
});
var zipFilename = $"{zipPath}//result.zip";
if (File.Exists(zipFilename))
{
File.Delete(zipFilename);
}
ZipFile.CreateFromDirectory(startPath, zipFilename, CompressionLevel.Fastest, true);
var result = System.IO.File.ReadAllBytes(zipFilename);
return result;
}
catch (Exception ex)
{
var a = ex;
return null;
}
}
currently im writing all files in my base directory(may be not a good idea).corrently i have to manually delete all folders and files to avoid exception/unwanted files. Can everything be written in memory?
What changes required to write all files and folder structure in memory?
No you can't. Not with the built in Dotnet any way.
As per my comment I would recommend storing the files in a custom location based on a Guid or similar. Eg:
"/xxxx-xxxx-xxxx-xxxx/Folder-To-Zip/....".
This would ensure you could handle multiple requests with the same files or similar file / folder names.
Then you just have to cleanup and delete the folder again afterwards so you don't run out of space.
Hope the below code does the job.
public async Task<byte[]> CreateZip(Guid ownerId)
{
try
{
string startPath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}_zipFolder");//folder to add
Directory.CreateDirectory(startPath);
var attachemnts = await ReadByOwnerId(ownerId);
attachemnts.Data = filterDuplicateAttachments(attachemnts.Data);
//filtering youtube urls
attachemnts.Data = attachemnts.Data.Where(i => !i.Flags.Equals("YoutubeUrl", StringComparison.OrdinalIgnoreCase)).ToList();
attachemnts.Data.ForEach(i =>
{
var fileLocalPath = $"{startPath}\\{i.Category}";
if (!Directory.Exists(fileLocalPath))
{
Directory.CreateDirectory(fileLocalPath);
}
using (var client = new WebClient())
{
client.DownloadFile(i.Url, $"{fileLocalPath}//{i.Flags ?? ""}_{i.FileName}");
}
});
using (var ms = new MemoryStream())
{
using (var zipArchive = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
System.IO.DirectoryInfo di = new DirectoryInfo(startPath);
var allFiles = di.GetFiles("",SearchOption.AllDirectories);
foreach (var attachment in allFiles)
{
var file = File.OpenRead(attachment.FullName);
var type = attachemnts.Data.Where(i => $"{ i.Flags ?? ""}_{ i.FileName}".Equals(attachment.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
var entry = zipArchive.CreateEntry($"{type.Category}/{attachment.Name}", CompressionLevel.Fastest);
using (var entryStream = entry.Open())
{
file.CopyTo(entryStream);
}
}
}
var result = ms.ToArray();
return result;
}
}
catch (Exception ex)
{
var a = ex;
return null;
}
}

How to read path from another method

I have a method which unzips file from my method, and I have a separate method which I want to create so it can read the unzip files and load them as needed.
private string UnzipFiles()
{
Chilkat.Zip zip = new Chilkat.Zip();
string zippedFilePath = #"C:\Users\TestData";
string unzippedFilePath = #"C:\Users\Temp";
bool success = zip.UnlockComponent("LIVECOZIP_3BzssvnbmYxp");
if (!success)
{
string errorMsg = zip.LastErrorText;
Console.WriteLine(errorMsg);
return errorMsg;
}
string[] newzip = (Directory.GetFiles(zippedFilePath));
foreach (string file in newzip)
{
success = zip.OpenZip(file);
{
Console.WriteLine(zip.LastErrorText);
}
zip.DecryptPassword = "hANhvU8MX7iq0f2M";
int unzipCount;
unzipCount = zip.Unzip(unzippedFilePath);
if (unzipCount < 0)
{
Console.WriteLine("unzipping file");
}
}
return unzippedFilePath;
The method below is where I need help. I want to call the method above and be able to read each file. Right now I am getting error.
public void LoadNewFile()
{
UnzipFiles();
foreach (String file in UnzipFiles)
//How to call each file?
{
userSelectedFilePath += file + Environment.NewLine;
names_of_files.Add(file);
}
Try this:
var path = UnzipFiles();
var unZippedFiles = Directory.GetFiles(path);
foreach (var file in unZippedFiles)
{
//tratata
}
I would say you need to change UnzipFiles to return a List of strings. Something like this:
private List<string> UnzipFiles()
{
Chilkat.Zip zip = new Chilkat.Zip();
string zippedFilePath = #"C:\Users\TestData";
string unzippedFilePath = #"C:\Users\Temp";
var unzippedFileList = new List<string>();
bool success = zip.UnlockComponent("LIVECOZIP_3BzssvnbmYxp");
if (!success)
{
string errorMsg = zip.LastErrorText;
Console.WriteLine(errorMsg);
return errorMsg;
}
string[] newzip = (Directory.GetFiles(zippedFilePath));
foreach (string file in newzip)
{
unzippedFileList.Add(file);
success = zip.OpenZip(file);
{
Console.WriteLine(zip.LastErrorText);
}
zip.DecryptPassword = "hANhvU8MX7iq0f2M";
int unzipCount;
unzipCount = zip.Unzip(unzippedFilePath);
if (unzipCount < 0)
{
Console.WriteLine("unzipping file");
}
}
return unzippedFileList;
}

Cannot open file c#

Can someone tell me why I have this error on the below code?
The procces cannot access the file "..." beucase it's using by another procces.
I closed the first StreamReader and after, when I intialize the StreamWriter, it crashed.
private static void removeSetting(string _class)
{
try
{
string[] allSettings = new string[20];
int iSettings = 0;
using (StreamReader FILE_READER = new StreamReader("DATA.properties"))
{
string line = FILE_READER.ReadLine();
while (line != null)
{
if (!line.Equals(""))
{
allSettings[iSettings] = line;
iSettings++;
}
line = FILE_READER.ReadLine();
}
}
using (StreamWriter FILE_WRITER = new StreamWriter("DATA.properties", false))
{
for (int i = 0; i <= iSettings; i++)
{
if (!allSettings[i].Split('=')[0].Equals(_class))
{
FILE_WRITER.WriteLine('\n' + allSettings[i] + '\n');
//i--;
}
}
}
}
catch (Exception ex)
{
}
}
public static void saveSetting(string _class, string value)
{
removeSetting(_class);
try
{
StreamWriter FILE_WRITER = new StreamWriter("DATA.properties", true);
FILE_WRITER.WriteLine( _class.ToString() +'='+ value);
FILE_WRITER.Close();
}
catch (Exception ex)
{
}
}
Solution: you need find a program which open this file and kill it or reload OS.
I suggest you want change "_class=oldValue" on "_class=newValue" by using _class like this
oldText:
dog=lock
cat=bob
use saveSetting(dog, fork)
newText:
cat=bob
dog=fork
you can use this method
private static void removeSetting(string _class,string value)
{
try
{
//read all lines from file
string[] allSettings = File.ReadAllLines("DATA.properties");
//divide string on string[] by '='
List<List<string>> strings = allSettings.Select(x => x.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries).ToList()).ToList();
//find all lines where first element equals _class
List<List<string>> result = strings.Where(x => x.First().Equals(_class)).Select(x=>new List<string>{_class, value}).ToList();
// convert string[] => string
string[] secondResult = result.Select(x => String.Join("=",x.ToArray())).ToArray();
List<List<string>> otherResult = strings.Where(x => !x.First().Equals(_class)).Select(x => x).ToList();
string[] firstResult = otherResult.Select(x => String.Join("=", x.ToArray())).ToArray();
//wrtie all lines in file
File.WriteAllLines("DATA.properties",firstResult);
File.AppendAllLines("DATA.properties", secondResult);
}
catch (Exception ex)
{
}
}

CPU utilisation goes to 100% while processing a text file

I have a master account file having more than 300000 records. This file is having Office, FA, UUID fields along with other fields. We have a webservice which retuns currently enrolled offices for pilot.
I need to generate a output file with unique UUIDs from master account file which are part of pilot. The below is my code.
public class Job
{
static Dictionary<string, string> UUIDOfficeFA = new Dictionary<string, string>();
static Dictionary<string, string> UUIDs = new Dictionary<string, string>();
static string PilotOfficeList = string.Empty;
/// <summary>
///
/// </summary>
public void RunJob()
{
try
{
DirectoryInfo directoryInfo = new DirectoryInfo(ConfigurationSettings.AppSettings["AccountFileFolder"]);
if (directoryInfo != null || directoryInfo.Exists == false)
{
FileInfo[] files = directoryInfo.GetFiles();
DateTime lastWrite = DateTime.MinValue;
FileInfo lastWritenFile = null;
foreach (FileInfo file in files)
{
if (file.LastWriteTime > lastWrite)
{
lastWrite = file.LastWriteTime;
lastWritenFile = file;
}
}
if (lastWritenFile != null)
{
if (RetrieveUUIDs(lastWritenFile))
{
WriteFile();
}
}
else
{
throw new Exception("No matching account file found for processing");
}
}
}
catch (Exception ex)
{
throw ex;
}
}
static void WriteFile()
{
try
{
string FileName = "Testfile_" + System.DateTime.Now.ToString("yyyyMMddHHmmss") + ".txt";
string Path = ConfigurationSettings.AppSettings["TestFolder"] + #"\" + FileName;
StringBuilder sb = new StringBuilder();
foreach (KeyValuePair<string, string> kvp in UUIDs)
{
sb.AppendLine(kvp.Value);
}
using (StreamWriter writer = File.AppendText(Path))
{
writer.Write(sb.ToString());
writer.Flush();
}
}
catch (Exception ex)
{
throw ex;
}
}
static bool RetrieveUUIDs(FileInfo file)
{
try
{
using (StreamReader sr = file.OpenText())
{
string accountFileData = null;
accountFileData = sr.ReadToEnd();
string[] str = accountFileData.Trim().Split(new string[] { "\n" }, StringSplitOptions.None);
List<string> AccountInfo = new List<string>(str);
if (AccountInfo.Count > 0)
{
TestWebservice client = new TestWebservice();
GetBrancheListRequest request = new GetBrancheListRequest();
GetBrancheListResponse response =client.GetBrancheList(request);
if (response != null)
{
PilotOfficeList = response.GetBrancheListResult;
if (string.IsNullOrEmpty(PilotOfficeList))
{
throw new Exception("No branch is enrolled for pilot");
}
}
}
foreach (string accountInfo in AccountInfo)
{
RetrieveUUID(accountInfo);
}
}
}
catch (Exception ex)
{
throw ex;
}
return true;
}
private static void RetrieveUUID(string line)
{
try
{
string UUID = line.Substring(2, 50).Trim();
string Office = line.Substring(444, 3).Trim();
string FA = line.Substring(447, 3).Trim();
if (!string.IsNullOrEmpty(PilotOfficeList))
{
if (!string.IsNullOrEmpty(UUID) || !string.IsNullOrEmpty(Office))
{
if (PilotOfficeList.IndexOf(Office) > -1)
{
if (!UUIDOfficeFA.ContainsKey(UUID + Office + FA))
{
UUIDOfficeFA.Add(UUID + Office + FA, UUID + Office + FA);
if (!UUIDs.ContainsKey(UUID))
{
UUIDs.Add(UUID, UUID);
}
}
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
}
The issue is when this program runs the CPU utilisation goes to 100%. Although entire job completes within 2 minutes but i can't move this on server beacuse it might cause issue for other apps. Please suggest how i can optimize this so that CPU doesn't goes to 100%.
Thank you so much for your help in prior.
Note- It appears that following are few major CPU utilization points
1-
accountFileData = sr.ReadToEnd();
2-
string[] str = accountFileData.Trim().Split(new string[] { "\n" }, StringSplitOptions.None);
3-
foreach (string accountInfo in AccountInfo)
{
RetrieveUUID(accountInfo);
}

Categories

Resources