I have a directory of around 30-40 folders that contain various backup files for a CRM system.
I have developed a script that downloads the files from a remote server, and places them in folders with YYYYMMDD, however due to space restrictions I now need to move the oldest folder from the directory. As the IT team at the company keep moving the folders between servers I cannot use the folder creation date!
What is the easiest option? I have looked at: deleting the oldest folder by identifying from the folder name and attempted to order the items then perform a move.
My other option was to take all of the folder names in the root directory, parse into a list of type time and date, select the lowest (oldest) option, then perform the file move?
how about something like this:
bool MoveOldestFolder(string initialFolderName, string destinationFolder)
{
// gets all top folders in your chosen location
var directories = System.IO.Directory.EnumerateDirectories(initialFolderName,"*", System.IO.SearchOption.TopDirectoryOnly);
// stores the oldest folder and it's date at the end of algorithm
DateTime outDate;
DateTime oldestDate = DateTime.MaxValue;
string resultFolder = string.Empty;
// just a temp variable
string tmp;
// using LINQ
directories.ToList().ForEach(p =>
{
tmp = new System.IO.FileInfo(p).Name; // get the name of the current folder
if (DateTime.TryParseExact(tmp,
"yyyyMMdd", // this is case sensitive!
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None,
out outDate)) // try using folder name as date that "should" be in yyyyMMdd format - if the conversion is successful and date is older than current outDate, then store folder name and date, else nothing
{
if (outDate.Date < oldestDate.Date)
{
oldestDate = outDate;
resultFolder = p;
}
}
});
// if we actually found a folder that is formatted in yyyyMMdd format
if (!oldestDate.Equals(DateTime.MaxValue))
{
try
{
System.IO.Directory.Move(resultFolder, destinationFolder);
return true;
}
catch(Exception ex)
{
// handle the excaption
return false;
}
}
else
{
// we didnt find anything
return false;
}
}
private void button1_Click(object sender, EventArgs e)
{
var initialFolderName = #"C:\initial";
var destinationFolder = #"c:\dest";
if (MoveOldestFolder(initialFolderName, destinationFolder))
{
// move was successful
}
else
{
// something went wrong
}
}
Other option would be to simply do what chrfin said but I wouldn't presume on everything being "dandy" in the folder structure. There is always a possibility that the folder name is not in YYYYMMDD format and that would probably cause some problems I imagine.
Anyway, the code could look something like this:
var directories = System.IO.Directory.EnumerateDirectories(initialFolderName,"*", System.IO.SearchOption.TopDirectoryOnly);
directories.ToList<string>().Sort();
var lastDir = directories.First();
Related
I have been using WinSCP to download files, periodically, from a Unix server to Windows server and it has been working with no issues. I also check if remote file is older or already exists (don't copy).
Now, I have to do the same but this time I have to download files and folders. Files are copied fine but folders aren't. When playing with the settings, I got it to copy the contents of the folder but they get copied to my root local folder; I thought WinSCP would copy everything.
In below code, LocalFolder is Z:\My_Data and LogRootFolder is /xyz/gtc/a00/
Folder structure on remote is /xyz/gtc/a00/ABCD/outcomes/ with subfolder "backup" that has many subfolders named as dates (e.g. /xyz/gtc/a00/ABCD/outcomes/backup/2021-06-23/)
Either none of "backup/2021-xx-xx/" files and folder are copied, or they are all copied to Z:\My_Data\ABCD
After setting up the session, called SFTP_Session:
string sRemotePath = LogRootFolder + "ABCD/outcomes/";
string sLocalFolder = Path.Combine(LocalFolder, #"ABCD\");
if (SFTP_Session.Opened)
{
using (SFTP_Session)
{
SFTP_Session.QueryReceived += (sender, e) =>
{
...
e.Continue();
};
//var opts = EnumerationOptions.EnumerateDirectories | EnumerationOptions.AllDirectories;
//IEnumerable<RemoteFileInfo> fileInfos = SFTP_Session.EnumerateRemoteFiles(sRemotePath, "*.dat", opts); <-- This copies files in folder(s) to m local root folder
Regex mask = new Regex(#"\.(dat|err)$", RegexOptions.IgnoreCase);
IEnumerable<RemoteFileInfo> fileInfos =
SFTP_Session.EnumerateRemoteFiles(sRemotePath, null, EnumerationOptions.AllDirectories)
.Where(fileInfo => mask.Match(fileInfo.Name).Success)
.ToList();
foreach (RemoteFileInfo fileInfo in fileInfos)
{
string localFilePath = Path.Combine(sLocalFolder, fileInfo.Name);
if (fileInfo.IsDirectory)
{
// Create local subdirectory, if it does not exist yet
if (!Directory.Exists(localFilePath))
{
Directory.CreateDirectory(localFilePath);
}
}
else
{
string remoteFilePath = RemotePath.EscapeFileMask(fileInfo.FullName);
// If file does not exist in local folder, download
if (!File.Exists(localFilePath))
{
bDownload = true;
}
else // If file exists in local folder but is older, download; else skip
{
DateTime remoteWriteTime = SFTP_Session.GetFileInfo(remoteFilePath).LastWriteTime;
DateTime localWriteTime = File.GetLastWriteTime(localFilePath);
if (remoteWriteTime > localWriteTime)
{
bDownload = true;
}
else
{
bDownload = false;
}
}
if (bDownload)
{
// Download file
TransferOptions oTrRes = new TransferOptions();
oTrRes.TransferMode = TransferMode.Automatic; //The Transfer Mode - Automatic, Binary, or Ascii
oTrRes.FilePermissions = null; //Permissions applied to remote files; null for default permissions. Can set user, Group, or other Read/Write/Execute permissions.
oTrRes.PreserveTimestamp = false; //Set last write time of destination file to that of source file - basically change the timestamp to match destination and source files.
oTrRes.ResumeSupport.State = TransferResumeSupportState.Off;
TransferOperationResult transferResult = SFTP_Session.GetFiles(remoteFilePath, localFilePath, false, oTrRes);//.Replace("\\","")); // I thought this would get files AND folders
// Throw on any error
transferResult.Check();
foreach (TransferEventArgs transfer in transferResult.Transfers)
{
// Store local file info in a data table for processing later
...
}
SessionRemoteExceptionCollection srec = transferResult.Failures;
foreach (SessionRemoteException sre in srec)
{
// Log errors
}
// Did the download succeeded?
if (!transferResult.IsSuccess)
{
// Log error (but continue with other files)
}
}
}
}
At the end, in local folder I see the files downloaded and copied and subfolders that I created (using above code) but no files in those folders. Can't see what I am missing here.
Your code basically synchronizes a remote directory to a local one.
Instead of fixing your code, you can simply replace most of it with a simple call to Session.SynchronizeDirectories:
https://winscp.net/eng/docs/library_session_synchronizedirectories
Try the synchronization first in WinSCP GUI to see if it does what you need.
If you need to do some processing with the synchronized files, use the SynchronizationResult returned by Session.SynchronizeDirectories. It contains a list of all synchronized files.
If you need to exclude some files from the synchronization, use TransferOptions.FileMask.
I have a question. I want to copy specific files in 'New folder' to 'Target' folder by clicking a button. In 'New folder' contains various of file with different name. For example: "abcUCU0001", "abbUCA0003", "hhhUCU0012", "aaaUCS0012" and many more. 'New folder' contains more than 1000 files and have same 10 letters in its name. I want to copy 10 files and its name must have "UCU". I don't know how to copy using (startsWith) starting with 4th letter.
Sorry for my bad grammar.
private void button1_Click(object sender, EventArgs e)
{
string FROM_DIR = #"C:\Users\Desktop\Source";
string TO_DIR = #"C:\Users\Desktop\Target";
DirectoryInfo diCopyForm = new DirectoryInfo(FROM_DIR);
DirectoryInfo[] fiDiskfiles = diCopyForm.GetDirectories();
string filename = "UCU";
int count = 0;
foreach (DirectoryInfo newfile in fiDiskfiles)
{
try
{
if (newfile.Name=="New folder")
{
foreach (FileInfo file in newfile.GetFiles())
{
if(file.FullName.StartsWith(filename))
{
File.Copy(file.FullName, Path.Combine(TO_DIR,file.Name));
count++;
if (count == 10)
{
break;
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
MessageBox.Show("success");
}
I expect after click a button, 10 files with name "UCU" will copied to Target folder.
If all the files are in the same directory (no sub-directories), then you can get all files using:
//assuming diCopyForm is the new folder reference
// ? denotes 1 character while * is multiple chars
var files = diCopyForm.GetFiles("???UCU*");
And then just copy them across. For more complex criteria, I would get all the files and use LINQ to filter through.
Details about the search pattern used
If there are a lot of files in the folder then it might be more efficient to use the EnumerateFiles method
The EnumerateFiles and GetFiles methods differ as follows: When you
use EnumerateFiles, you can start enumerating the collection of names
before the whole collection is returned; when you use GetFiles, you
must wait for the whole array of names to be returned before you can
access the array. Therefore, when you are working with many files and
directories, EnumerateFiles can be more efficient.
You can check if file name has "UCU" in 4th position with string.IndexOf:
//string filename = "UCU";
if (file.FullName.IndexOf(filename) == 3)
I need to convert images(like .jpg) to PDF files for an assignment for school. I have a ListBox where I put the pages of the PDF file, so the user can reorder the list and convert the files in that order.
I have the files in a temporary folder in order to get the files there to convert them to PDF.
My problem here is : how do I convert the files with the order that the user had chosen?
I already searched and I tried to do a Class with the strings ID and Name so i get the ID from the item in the ListBox and change it on a new list. And i think after, I do a foreach() loop where I get the files from the temporary folder and merge them in a new PDF file, but to do in the order I want, I think I have to compare the name of the file with the name in the list and, if it matches, convert and add it, if not, pass to the next file.
But I don't know how to do it.
Can please someone help me getting this right?
Thanks in advance!
I'm sending my code to:
//the open files button
private void proc2_Click(object sender, EventArgs e)
{
OpenFileDialog dialogo = new OpenFileDialog();
dialogo.Title = "Search files";
dialogo.InitialDirectory = #"E:\";
dialogo.Filter = "Images (.bmp,.jpg,.png,.tiff,.tif) |*.bmp;*.jpg;*.png;*tiff;*tif|All of the files (*.*)|*.*";
DialogResult resposta = dialogo.ShowDialog();
if (resposta == DialogResult.OK)
{
string caminhoCompleto = dialogo.FileName;
caminho2 = dialogo.SafeFileName;
caminhotb2.Text = caminhoCompleto;
string fish = "";
string path = #"C:\temporario";
if(Directory.Exists(path))
{
fish=Path.Combine(path, caminho2);
}
else
{
Directory.CreateDirectory(path);
fish = Path.Combine(path, caminho2);
}
File.Create(fish);
listaimg.Items.Add(caminho2);
}
}
public string[] GetFilesImg4() //jpg files
{
if (!Directory.Exists(#"C:\temporario"))
{
Directory.CreateDirectory(#"C:\temporario");
}
DirectoryInfo dirInfo = new DirectoryInfo(#"C:\temporario");
FileInfo[] fileInfos4 = dirInfo.GetFiles("*.jpg");
foreach (FileInfo info in fileInfos4)
{
if (info.Name.IndexOf("protected") == -1)
list4.Add(info.FullName);
}
return (string[])list4.ToArray(typeof(string));
}
If both actions happen in the same process, you can just store the list of file names in memory (and you already do add them to listaimg):
public string[] GetFilesImg4() //jpg files
{
string tempPath = #"C:\temporario";
if (!Directory.Exists(tempPath))
{
foreach (string filename in listimga.Items)
{
if (!filename.Contains("protected"))
list4.Add(Path.Combine(tempPath, filename);
}
}
return (string[])list4.ToArray(typeof(string));
}
if these are different processes then you can just dump content of your listimga at some point and then read it from the same file. In the example below I store it to file named "order.txt" in the same directory, but logic may be more complicated, such as merging several files with a timestamp and such.
// somewhere in after selecting all files
File.WriteAllLines(#"c:\temporario\order.txt", listimga.Items.Select(t=>t.ToString()));
public string[] GetFilesImg4() //jpg files
{
string tempPath = #"C:\temporario";
if (!Directory.Exists(tempPath))
{
var orderedFilenames = File.ReadAllLines(Path.Combine(tempPath, "order.txt")); // list of files loaded in order
foreach (string filename in orderedFilenames)
{
if (!filename.Contains("protected"))
list4.Add(Path.Combine(tempPath, filename);
}
}
return (string[])list4.ToArray(typeof(string));
}
it's also a good idea to examine available method on a class, such as in this case string.IndexOf(s) == -1 is equivalent to !string.Contains(s) and the latter is much more readable at least for an English speaking person.
I also noticed that your users have to select documents one by one, but FileOpen dialogs allow to select multiple files at a time, and I believe it preserves the order of selection as well.
If order of selection is important and file open dialogs don't preserve order or users find it hard to follow you can still use multiple file selection open dialog and then allow to reorder your listimga list box to get the order right.
How to connect server already hosted on IIS Website Folder and compare the Local Client Folder?
This is my Website URL on localhost
IISHostedWebsite/Updates //Folder in Website
I need to compare in this url update folder files with my local client machine's D:\Updates folder.
If new updates available into server it will copy to my D:\Updates folder.
How can we achieve this sort of situation ?
I have some code that in C#
var directory = new DirectoryInfo(#"D:\\Anand\\Work\\FolderCheck\\Server");
var myFile = (from f in directory.GetFiles()
orderby f.LastWriteTime descending
select f).First();
This code generates the latest updated file from folder
The MSDeploy tool (http://www.iis.net/downloads/microsoft/web-deploy) was designed to solve this problem. It lets you compare IIS virtual directories to other directories, and synchronize them if needed. It can also be used just as a diff tool.
In your example, after installing MSDeploy, you could do the following:
msdeploy.exe -verb:sync -source:contentPath="IISHostedWebSite/Updates" -dest:contentPath=d:\updates -whatIf
This command will show the list of changes needed to update d:\updates to look like IISHostedWebSites/Updates. If you remove the "-whatif" it will actually do the changes.
You can also call the MSDeploy programatically to do the same thing.
Also the problem with your code snippet is that you wouldn't detect deleted files from source that also need to be deleted from destination.
Here my code is for Getting Files from Directory and Check Whether are same if not It will Showing No updates Found and After that It will Check latest Files Available into Folder if Available then Copy this Files and Move to Destination Folder This is my Task but i have completed my code in Latest updated file i get from this code but i dont no how this files are copy into destination folder
string serverPath = #"D:\Anand\Work\FolderCheck\Server"; //Source File
string clientPath = #"D:\Anand\Work\FolderCheck\Client"; //destination Folder
private static bool CompareFileSizes(string fileServer, string fileClient)
{
bool fileSizeEqual = true;
if (fileServer.Length == fileClient.Length) // Compare file sizes
{
fileSizeEqual = false; // File sizes are not equal therefore files are not identical
}
return fileSizeEqual;
}
try
{
if (!File.Exists(serverPath) || !File.Exists(clientPath))
{
try
{
var Server = Path.GetFileName(serverPath);
var Client = Path.GetFileName(clientPath);
string ServerFile = Server.ToString();
string ClientFile = Client.ToString();
if (CompareFileSizes(ServerFile, ClientFile))
{
lblServerMsg.Text = "No Updates are Found: ";
}
else
{
var directoryServer = new DirectoryInfo(#"D:\Anand\Work\FolderCheck\Server"); //check latest Available File From Server
var myFile = (from f in directoryServer.GetFiles()
orderby f.LastWriteTime descending
select f).First();
lblServerMsg.Text = "Updates Are Available Click for Update Button:";
btnCheckUpates.Visible = false;
btnUpdates.Visible = true;
}
}
catch (Exception msg)
{
lblServerMsg.Text = "No Updates are Found: " + msg.Message;
}
}
else
{
throw new FileNotFoundException();
}
}
catch (FileNotFoundException ex)
{
lblServerMsg.Text = ex.Message;
}
Above code i have done Get latest File from Source Folder but i dont no how to
var myFile = (from f in directoryServer.GetFiles()
orderby f.LastWriteTime descending
select f).First();
Above doe myFile are latest File from Source Folder this i want to copy into Destination Folder
I am currently developing a tool that will find all files, from the previous day, and move them from one folder to another on the same server. I am not hitting permission issues but I am getting stuck on the IF statement. Once the application finds a file, move to the other folder for further processing. My issue is that I am unable to find all files with just the date of yesterday and move them. I have supplied my code below and it is almost there (or at least that's what I tell myself). Thanks ahead of time for any assistance.
private void Form1_Load(object sender, EventArgs e)
{
DateTime past = DateTime.Today.AddDays(-1);
txtSourceFolderCount.Text = past.ToShortDateString();
//efile originally start here
var sourceDir = #"\\DIS2\EFilingXML\Archive";
//application moves to archive
var destDir = #"\\DIS2\EFilingXML";
//only XML files are accepted
//var pattern = "*.xml";
DirectoryInfo source = new DirectoryInfo(sourceDir);
// Get info of each file into the directory
foreach (FileInfo fi in source.GetFiles())
{
var creationTime = fi.LastWriteTime;
if (creationTime == past && creationTime < DateTime.Today)
{
fi.MoveTo(Path.Combine(destDir, fi.ToString()));
}
}
}
My issue is that I am unable to find all files with just the date of
yesterday and move them.
Two issues:
1) You are only using File.Name when you try to call the static System.IO.File.GetCreationTime method. This static method has no context other than the short File.Name with a value like "MyFile.xml" and no path attached.
2) You'll pickup files from today unless you add a second qualifier to your if statement like below:
//gets all files in source directory & moves to destination directory(archive)
foreach (var file in new DirectoryInfo(sourceDir).GetFiles(pattern))
{
DateTime dt = File.GetCreationTime(file.FullName);
if (dt >= DateTime.Today.AddDays(-1) && dt < DateTime.Today)
{
file.MoveTo(Path.Combine(destDir, file.Name));
}
}