How to use OrderByDescending on Properties using IListFileItem? - c#

I have following code which will return all list items (files and folders) of specific given azure storage path.
I want to filter it using OrderByDescending based on Property LastModified
How to achieve this ?
// Get list of all files/directories on the file share
CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["storageConnectionString"]);
CloudFileClient fileClient = cloudStorageAccount.CreateCloudFileClient();
CloudFileShare fileShare = fileClient.GetShareReference(ConfigurationManager.AppSettings["shareName"]);
var sourceName = fileShare.GetRootDirectoryReference().GetDirectoryReference((ConfigurationManager.AppSettings["sourceName"]));
IEnumerable<IListFileItem> fileList = sourceName.ListFilesAndDirectories();
var test = (fileList.OrderByDescending(t => t.Uri.AbsolutePath).FirstOrDefault());
I tried with casting but LastModified is null
fileList.ToList().ForEach(x => ((CloudFileDirectory)x).FetchAttributes());
GetAllSubDir(fileList.OrderByDescending(t => ((CloudFileDirectory)t).Properties.LastModified.Value).FirstOrDefault());
instead of Uri.AbsolutePath I want to use LastModified.

Have a try at following code. You need to get all files first because ListFilesAndDirectories only returns files and directory in a single level.
List<CloudFile> list = new List<CloudFile>();
public void Test()
{
CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["storageConnectionString"]);
CloudFileClient fileClient = cloudStorageAccount.CreateCloudFileClient();
CloudFileShare fileShare =
fileClient.GetShareReference(ConfigurationManager.AppSettings["shareName"]);
var sourceName = fileShare.GetRootDirectoryReference().GetDirectoryReference((ConfigurationManager.AppSettings["sourceName"]));
IEnumerable<IListFileItem> fileList = sourceName.ListFilesAndDirectories();
listFile(fileList);
var test = (from file in list
orderby file.Properties.LastModified descending
select file).FirstOrDefault();
}
// detect all files in the directory
public void listFile(IEnumerable<IListFileItem> results)
{
foreach (IListFileItem fileItem in results)
{
if (fileItem.GetType() == typeof(CloudFileDirectory))
{
CloudFileDirectory directory = (CloudFileDirectory)fileItem;
var res = directory.ListFilesAndDirectories();
listFile(res);
}
else
{
CloudFile file = (CloudFile)fileItem;
file.FetchAttributes();
list.Add(file);
}
}
}

public static void CheckDate()
{
CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["storageConnectionString"]);
CloudFileClient fileClient = cloudStorageAccount.CreateCloudFileClient();
CloudFileShare fileShare =
fileClient.GetShareReference(ConfigurationManager.AppSettings["shareName"]);
var sourceName = fileShare.GetRootDirectoryReference().GetDirectoryReference((ConfigurationManager.AppSettings["sourceName"]));
IEnumerable<IListFileItem> fileList = sourceName.ListFilesAndDirectories();
listFile(fileList);
var latestFile = (from file in filedataList
orderby file.Properties.LastModified descending
select file).FirstOrDefault();
Console.WriteLine(" LastModified Datetime - " + latestFile.Properties.LastModified.Value.DateTime);
}
public static void listFile(IEnumerable<IListFileItem> results)
{
foreach (var item in results)
{
if (item.GetType() == typeof(CloudFileDirectory))
{
CloudFileDirectory dir = (CloudFileDirectory)item;
dir.FetchAttributes();
dirList.Add(dir);
}
else
{
CloudFile file = (CloudFile)item;
file.FetchAttributes();
filedataList.Add(file);
}
}
if (dirList.Count > 0)
{
var latestDir = (from dir in dirList
orderby dir.Properties.LastModified descending
select dir).FirstOrDefault();
dirList.Clear();
var result = latestDir.ListFilesAndDirectories();
listFile(result);
}
}

Related

Enumerate directories that match wildcard

This is my folder structure:
c:\logs\v1\api1
c:\logs\v1\api2
c:\logs\v2\api1
c:\logs\v2\api2
c:\logs\other
I would like to get all folders that match this pattern:
c:\logs\v*\api*
So, what I want is to get list of theese:
c:\logs\v1\api1
c:\logs\v1\api2
c:\logs\v2\api1
c:\logs\v2\api2
This doesn't work:
var result = Directory.GetDirectories(#"c:\logs\v*\api*");
Because System.IO.IOException: 'The filename, directory name, or volume label syntax is incorrect. : 'c:\logs\v*\api*'' is thrown
This doesn't work:
var directory = #"c:\logs\v*\api*";
var rootDirectory = Directory.GetDirectoryRoot(directory);
var remainingPath = directory.Substring(rootDirectory.Length);
Console.WriteLine($"remainingPath: {remainingPath}");
var result = Directory.GetDirectories(rootDirectory, remainingPath);
Because System.IO.IOException: 'The filename, directory name, or volume label syntax is incorrect. : 'c:\logs\v*'' is thrown
This works:
public static IEnumerable<string> ResolveDirectories(string path)
{
if (path.Contains("*") || path.Contains("?"))
{
var parts = new Regex(#"[\\/](?=[^\\/]*[\*?])").Split(path, 2);
var searchRoot = parts[0];
var searchPatterns = parts[1].Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
foreach (var dir in ResolveWildcards(searchRoot, searchPatterns))
yield return dir;
}
else
{
yield return path;
}
}
public static IEnumerable<string> ResolveWildcards(string searchRoot, string[] searchPatterns)
{
if (Directory.Exists(searchRoot))
{
// use next pattern to search in a search root
var next = searchPatterns[0];
// leave the rest for recursion
var rest = searchPatterns.Skip(1).ToArray();
if (!searchRoot.EndsWith("\\"))
searchRoot += "\\";
foreach (var dir in Directory.EnumerateDirectories(searchRoot, next))
{
// if nothing left (last pattern) - return it
if (rest.Length == 0)
yield return dir;
else
{
// otherwise search with rest patterns in freshly found directory
foreach (var sub in ResolveWildcards(dir, rest))
yield return sub;
}
}
}
}
But I don't like how this is coded.
Thanks to #Alessandro_D'Andria I created this:
public static IEnumerable<string> ResolveDirectories(string path)
{
var parts = new Regex(#"[\\/](?=[^\\/]*[\*?])").Split(path, 2);
var root = parts[0];
var part = #".*\\" + parts[1].Replace(#"\", #"\\");
var regex = new Regex(part);
var dirs = Directory
.EnumerateDirectories(
root,
"*",
SearchOption.AllDirectories)
.Where(x => regex.IsMatch(x))
.ToList();
return dirs;
}
But both solutions are big mess. Is there any more elegant solution?
I think you are complicating, just using some regex and linq should be enough:
var regex = new Regex(#".*\\logs\\v\d+\\api\d+");
var dirs = Directory
.EnumerateDirectories(
#"C:\logs",
"*",
SearchOption.AllDirectories)
.Where(x => regex.IsMatch(x));

How can I loop over sub folders in Assets folder?

string selectedPath = GetPath();
var subFolders = AssetDatabase.GetSubFolders(selectedPath);
List<string> paths = new List<string>();
foreach(string path in subFolders)
{
paths.Add(path);
}
For example the subFolders is Assets/My Folder
but under My Folder there are many more subfolders.
AssetDatabase.GetSubFolders don't make recursive it's getting the first sub folder only.
I want to get all the sub folders recursive.
I tried :
List paths = new List();
foreach(string path in subFolders)
{
paths.Add(path);
}
but it's still giving me only the first sub folder.
This is how I'm getting the selected path name in the Assets :
[MenuItem("Assets/Get Path")]
private static string GetClickedDirFullPath()
{
string clickedAssetGuid = Selection.assetGUIDs[0];
string clickedPath = AssetDatabase.GUIDToAssetPath(clickedAssetGuid);
string clickedPathFull = Path.Combine(Directory.GetCurrentDirectory(), clickedPath);
FileAttributes attr = File.GetAttributes(clickedPathFull);
return attr.HasFlag(FileAttributes.Directory) ? clickedPathFull : Path.GetDirectoryName(clickedPathFull);
}
[MenuItem("Assets/Get Path")]
private static string GetPath()
{
string path = GetClickedDirFullPath();
int index = path.IndexOf("Assets");
string result = path.Substring(index);
return result;
}
You could simply make it recursive using List<T>.AddRange like
private static string[] GetSubFoldersRecursive(string root)
{
var paths = new List<string>();
// If there are no further subfolders then AssetDatabase.GetSubFolders returns
// an empty array => foreach will not be executed
// This is the exit point for the recursion
foreach (var path in AssetDatabase.GetSubFolders(root))
{
// add this subfolder itself
paths.Add(path);
// If this has no further subfolders then simply no new elements are added
paths.AddRange(GetSubFoldersRecursive(path));
}
return paths.ToArray();
}
So e.g.
[ContextMenu("Test")]
private void Test()
{
var sb = new StringBuilder();
var folders = SubFolders("Assets");
if(folders.Length > 0)
{
foreach (var folder in SubFolders("Assets"))
{
sb.Append(folder).Append('\n');
}
}
else
{
sb.Append(" << The given path has no subfolders! >>");
}
Debug.Log(sb.ToString());
}
will print out the entire project's folder structure.
For
I get
Assets/Example 1
Assets/Example 1/SubFolder A
Assets/Example 1/SubFolder B
Assets/Example 1/SubFolder C
Assets/Example 2
Assets/Example 2/SubFolder A
Assets/Example 2/SubFolder A/SubSubFolder A
So in your case it would be
string selectedPath = GetPath();
var folders = SubFolders(selectedPath);
foreach(var path in folders)
{
...
}
Try this code for get recursive folder path
//this is your code
string selectedPath = GetPath();
var subFolders = AssetDatabase.GetSubFolders(selectedPath);
List<string> paths = new List<string>();
if(subFolders != null)
{
foreach(string path in subFolders)
{
GetAllRecursiveFolder(path,ref paths);
}
}
else
{
paths.add(selectedPath);
}
public void GetAllRecursiveFolder(string currentPath,ref List<string> paths)
{
var subFolders = AssetDatabase.GetSubFolders(currentPath);
if(subFolders != null)
{
foreach(string path in subFolders)
{
GetAllRecursiveFolder(path,ref paths);// Get recursive folder path, and stored in ref variable
}
}
else
{
paths.add(currentPath);
}
}

Get current iteration from TFS

I need to get current iteration's path from TFS project. I'm able to use REST API query <server>/<project>/_apis/work/teamsettings/iterations?$timeframe=current&api-version=v2.0-preview but I don't want to perform query and parse JSON response. I want to use appropriate API in .NET client libraries for VSTS (and TFS).
I have an instance of the VssConnection. How can I get the path of current iteration from this object?
You can get the current iteration using the WorkHttpClient without having to iterate:
var creds = new VssBasicCredential(string.Empty, "personalaccesstoken");
VssConnection connection = new VssConnection(new Uri("url"), creds);
var workClient = connection.GetClient<WorkHttpClient>();
var teamContext = new TeamContext(teamId);
teamContext.ProjectId = projectId;
var currentIteration = await workClient.GetTeamIterationsAsync(teamContext, "current");
The simplest way I've found to do it was by using ICommonStructureService4 and TeamSettingsConfigurationService methods:
static TfsTeamProjectCollection _tfs = TfsTeamProjectCollectionFactory
.GetTeamProjectCollection("<tfsUri>")
(...)
static string GetCurrentIterationPath()
{
var css = _tfs.GetService<ICommonStructureService4>();
var teamProjectName = "<teamProjectName>";
var project = css.GetProjectFromName(teamProjectName);
var teamName = "<teamName>";
var teamSettingsStore =
_tfs.GetService<TeamSettingsConfigurationService>();
var settings = teamSettingsStore
.GetTeamConfigurationsForUser(new[] { project.Uri })
.Where(c => c.TeamName == teamName)
.FirstOrDefault();
if (settings == null)
{
var currentUser = System.Threading.Thread.CurrentPrincipal.Identity.Name;
throw new InvalidOperationException(
$"User '{currentUser}' doesn't have access to '{teamName}' team project.");
}
return settings.TeamSettings.CurrentIterationPath;
}
And returning the TeamSettings.CurrentIterationPath property.
I found a solution using VssConnection:
var workClient = connection.GetClient<WorkHttpClient>();
var iterations = workClient.GetTeamIterationsAsync(new TeamContext("project-name")).Result;
var currentDate = DateTime.Now.Date;
var currentIterationPath = iterations
.Select(i => new { i.Path, i.Attributes })
.FirstOrDefault(i => currentDate >= i.Attributes.StartDate &&
currentDate <= i.Attributes.FinishDate)
?.Path;
Here is a case provides a solution: Get the current iteration path from TFS
private static XmlNode currentIterationNode;
TfsTeamProjectCollection tpc = TFSConncetion(#"http://tfs/url");
ICommonStructureService4 css = tpc.GetService<ICommonStructureService4>();;
WorkItemStore workItemStore = new WorkItemStore(tpc);
foreach (Project teamProject in workItemStore.Projects)
{
if (teamProject.Name.Equals("TeamProjectNameGoesHere"))
{
NodeInfo[] structures = css.ListStructures(teamProject.Uri.ToString());
NodeInfo iterations = structures.FirstOrDefault(n => n.StructureType.Equals("ProjectLifecycle"));
if (iterations != null)
{
XmlElement iterationsTree = css.GetNodesXml(new[] { iterations.Uri }, true);
XmlNodeList nodeList = iterationsTree.ChildNodes;
currentIterationNode = FindCurrentIteration(nodeList);
String currentIterationPath = currentIterationNode.Attributes["Path"].Value;
}
}
}

Create a sub folder in a container Azure C programmatically

At the moment I have a number of containers. Foreach container I want to add an empty folder from a different storage account just containing the folders name. I then want to populate it with the necessary data.
I'm not sure if there is an property that can create a folder within a container.
Here I have two containers one from my sourceAccount and the other to my targetAccount. I'm sending data from my sourceAccout to my tagetAccount. In my target account within my container dayBlob I want to create the sub folder.
In this section of code I'm getting all the containers. When I get these containers I get the name of each of them. I want to add sub folders in my target container with the names that I get in my foreach
foreach (var items in containers)
{
var containerName = items.Name;
}
My code is as follows
static CloudStorageAccount sourceAccount = new CloudStorageAccount(new StorageCredentials("name", "key"), true);
static CloudStorageAccount targertAccount = new CloudStorageAccount(new StorageCredentials("name", "key"), true);
static void Main(string[] args)
{
DateTime dateToday = DateTime.Today;
DateTime date = new DateTime();
DateTime dateutc = TimeZoneInfo.ConvertTimeToUtc(date);
TimeSpan startDay = new TimeSpan(00, 00, 00);
TimeSpan endDay = new TimeSpan(23, 59, 59);
var sourceClient = sourceAccount.CreateCloudBlobClient();
var targetClient = targetAccount.CreateCloudBlobClient();
var testContainer = sourceClient.GetContainerReference("test");
var sourceContainer = sourceClient.GetContainerReference("downloads");
var itDropBoxContainer = sourceClient.GetContainerReference("it-dropbox");
var dayBlob = targetClient.GetContainerReference($"day{dateToday.Day}");
date = DateTime.Parse($"{dateToday.Day}/{dateToday.Month}/{dateToday.Year}");
var start = date + startDay;
var end = date + endDay;
IEnumerable<CloudBlobContainer> containers = sourceClient.ListContainers();
foreach (var items in containers)
{
var containerName = items.Name;
}
foreach (IListBlobItem item in testContainer.ListBlobs(useFlatBlobListing: true))
{
var blob = item as CloudBlockBlob;
var modificationDate = blob.Properties.LastModified;
// to set the modfication date as local time
var britishZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
var lastModified = TimeZoneInfo.ConvertTime((DateTimeOffset)modificationDate, britishZone);
if (lastModified > start && lastModified < end)
{
try
{
if (blob != null)
{
CloudBlockBlob sourceBlob = testContainer.GetBlockBlobReference(blob.Name);
CloudBlockBlob targetBlob = dayBlob.GetBlockBlobReference(blob.Name);
Console.WriteLine($"Successfully created a snapshot of blob {blob.Name}");
}
}
catch (Exception ex)
{
ExceptionHandler.LogError(ex, "Failed to copy to the target folder");
}
}
else
{
Console.WriteLine($"Failed to create a snapshot of blob {blob.Name}");
}
}
}
As #GauravMantri mentioned, we can't create folder without independently because folder is a virtual entity in blob storage. You don't need to create a folder before using it. For example, we can get the reference of folder1 even if the folder1 is not exist in the container.
var directory = container.GetDirectoryReference("folder1");
// Retrieve reference to a blob named "myblob".
CloudBlockBlob blockBlob = directory.GetBlockBlobReference("myblob");
If you did want to create a folder, you did need to create a blob within it.
var directory = container.GetDirectoryReference("folder1");
CloudBlockBlob blockBlob = directory.GetBlockBlobReference("dummy.txt");
blockBlob.UploadFromByteArray(new byte[0], 0, 0);
To list all the folders in a container, you could use following code.
var folders = container.ListBlobs().Where(b => b as CloudBlobDirectory != null).ToList();
foreach (var folder in folders)
{
Console.WriteLine(folder.Uri);
}

Treeview with different folder classes

I'm trying to pull together a treeview with folders of mixed classes. The root folders are one class and subfolders are another, like this:
Root Folder #1 <-- DirectoryItem class
--Sub Folder <-- SubDirectoryItem class
----file <-- FileItem class
Root Folder #2 <-- DirectoryItem class
--Sub Folder <-- SubDirectoryItem class
----file <-- FileItem class
I've been attempting to combine two different recursive methods so the subfolders are retrieved as "SubDirectoryItems" instead of "DirectoryItem" I'll spare that code attempt due to lack of clarify, but I'm wondering if there's a better approach?
class ItemProvider
{
public List<Item> GetItems(string path, SearchOption searchOption)
{
var items = new List<Item>();
var dirInfo = new DirectoryInfo(path);
foreach (var directory in dirInfo.GetDirectories("*.*", SearchOption.TopDirectoryOnly))
{
var item = new DirectoryItem
{
Name = directory.Name,
Path = directory.FullName,
Items = GetItems(directory.FullName, SearchOption.AllDirectories)
};
items.Add(item);
}
foreach (var subdirectory in dirInfo.GetDirectories("*.*", SearchOption.TopDirectoryOnly))
{
var item = new SubDirectoryItem()
{
Name = subdirectory.Name,
Path = subdirectory.FullName,
Items = GetItems(subdirectory.FullName, SearchOption.AllDirectories)
};
items.Add(item);
}
foreach (var file in dirInfo.GetFiles())
{
var item = new FileItem
{
Name = file.Name,
Path = file.FullName
};
items.Add(item);
}
return items;
}
}
}
I was able to figure it out. I made the first list TopDirectoryOnly then pulled in the rest of the items via a 2nd list for AllDirectories. Here's the code in case it helps any other beginners (like me):
class ItemProvider
{
public List<Item> GetItems(string path, SearchOption searchOption)
{
var items = new List<Item>();
var dirInfo = new DirectoryInfo(path);
foreach (var directory in dirInfo.GetDirectories("*.*", SearchOption.TopDirectoryOnly))
{
var item = new DirectoryItem
{
Name = directory.Name,
Path = directory.FullName,
Items = GetSubItems(directory.FullName, SearchOption.AllDirectories)
};
items.Add(item);
}
return items;
}
public List<Item> GetSubItems(string path, SearchOption searchOption)
{
var items = new List<Item>();
var dirInfo = new DirectoryInfo(path);
foreach (var subdirectory in dirInfo.GetDirectories("*.*", SearchOption.AllDirectories))
{
var item = new SubDirectoryItem()
{
Name = subdirectory.Name,
Path = subdirectory.FullName,
Items = GetSubItems(subdirectory.FullName, SearchOption.AllDirectories)
};
items.Add(item);
}
foreach (var file in dirInfo.GetFiles())
{
var item = new FileItem
{
Name = file.Name,
Path = file.FullName
};
items.Add(item);
}
return items;
}
}

Categories