I am trying to loop after all files in a folder and all subfolders as deep as it goes from the first folder.
I have found a way but I think it's stupid and is probably a way better method to do it.
The code loops through the first folder and all files. After that it loops again the subfolders then files and again for the third time.
Is there some other way I can do this? just choose one folder then it loops down the hierarchy automatically.
static void ReadAllSubs(string siteUrl, string siteFolderPath, string localTempLocation)
{
ClientContext ctx = new ClientContext(siteUrl);
ctx.AuthenticationMode = ClientAuthenticationMode.Default;
SecureString passWord = new SecureString();
string pwd = "xxx";
foreach (char c in pwd.ToCharArray()) passWord.AppendChar(c);
ctx.Credentials = new SharePointOnlineCredentials("test#test.com", passWord);
FolderCollection folderCollection = ctx.Web.GetFolderByServerRelativeUrl("Delte%20dokumenter/07 - Detaljprosjekt").Folders;
// Don't just load the folder collection, but the property on each folder too
ctx.Load(folderCollection, fs => fs.Include(f => f.ListItemAllFields));
// Actually fetch the data
ctx.ExecuteQuery();
foreach (Folder folder in folderCollection)
{
//LOOP MAIN FOLDER
Console.WriteLine("---------------FIRST LAYER FOLDER---------------------");
var item = folder.ListItemAllFields;
var folderpath = item["FileRef"];
FolderCollection LoopFolder = ctx.Web.GetFolderByServerRelativeUrl(folderpath.ToString()).Folders;
ctx.Load(LoopFolder, fs => fs.Include(f => f.ListItemAllFields));
ctx.ExecuteQuery();
Console.WriteLine(folderpath);
//LOOP ALL FILES IN FIRST MAIN FOLDER
FileCollection mainfiles = ctx.Web.GetFolderByServerRelativeUrl(folderpath.ToString()).Files;
ctx.Load(mainfiles);
ctx.ExecuteQuery();
Console.WriteLine("---------------FIRST LAYER FILES---------------------");
foreach (File mainfile in mainfiles)
{
Console.WriteLine(mainfile.Name);
Console.WriteLine(mainfile.MajorVersion);
}
//LOOP SUBFOLDER
Console.WriteLine("---------------SECOUND LAYER FOLDER---------------------");
foreach (Folder ff in LoopFolder)
{
var subitem = ff.ListItemAllFields;
var folderpathsub = subitem["FileRef"];
Console.WriteLine(folderpathsub);
//LOOP ALL FILES IN FIRST SUBFOLDER
FileCollection files = ctx.Web.GetFolderByServerRelativeUrl(folderpathsub.ToString()).Files;
ctx.Load(files);
ctx.ExecuteQuery();
Console.WriteLine("---------------SECOUND LAYER FILES---------------------");
foreach (File file in files)
{
Console.WriteLine(file.Name);
Console.WriteLine(file.MajorVersion);
}
var created = (DateTime)item["Created"];
var modified = (DateTime)item["Modified"];
Console.WriteLine("---------------THIRD LAYER FOLDER---------------------");
FolderCollection ThirdLoopFolder = ctx.Web.GetFolderByServerRelativeUrl(folderpathsub.ToString()).Folders;
ctx.Load(ThirdLoopFolder, fs => fs.Include(f => f.ListItemAllFields));
ctx.ExecuteQuery();
foreach (Folder fff in ThirdLoopFolder)
{
var item3 = fff.ListItemAllFields;
var folderpath3 = item3["FileRef"];
Console.WriteLine(folderpath3);
//LOOP ALL FILES IN THIRD SUBFOLDER
FileCollection thirdfiles = ctx.Web.GetFolderByServerRelativeUrl(folderpath3.ToString()).Files;
ctx.Load(thirdfiles);
ctx.ExecuteQuery();
Console.WriteLine("---------------THIRD LAYER FILES---------------------");
foreach (File file in thirdfiles)
{
Console.WriteLine(file.Name);
Console.WriteLine(file.MajorVersion);
}
}
}
}
}
I may propose two solutions.
First method
The first would be a recursive approach similar to Your solution.
private static void UseRecursiveMethodToGetAllItems()
{
using (var context = new ClientContext(WebUrl))
{
context.Credentials = new SharePointOnlineCredentials(UserName, Password);
var rootFolders = context.Web.GetFolderByServerRelativeUrl(LibName).Folders;
context.Load(rootFolders, folders => folders.Include(f => f.ListItemAllFields));
context.ExecuteQuery();
foreach (var folder in rootFolders)
{
GetFilesAndFolders(context, folder);
}
Console.ReadLine();
}
}
private static void GetFilesAndFolders(ClientContext context, Folder folder)
{
if (folder != null && folder.ListItemAllFields.FieldValues.Count > 0)
{
Console.WriteLine($"Folder - {folder.ListItemAllFields.FieldValues["FileLeafRef"]}");
var fileCollection = folder.Files;
context.Load(fileCollection, files => files.Include(f => f.ListItemAllFields));
context.ExecuteQuery();
foreach(var file in fileCollection)
{
Console.WriteLine($" -> {file.ListItemAllFields.FieldValues["FileLeafRef"]}");
}
var subFolderCollection = folder.Folders;
context.Load(subFolderCollection, folders => folders.Include(f => f.ListItemAllFields));
context.ExecuteQuery();
foreach (var subFolder in subFolderCollection)
{
GetFilesAndFolders(context, subFolder);
}
}
}
the first function does the authentication to the given WebUrl and gets the folders from the root folder (which is the name of the library). Then the second method is recursive. First gets all files from the current folder and prints them to the console, after that the next step is to query the subfolders in this folder and then do the same method.
I have created a sample library with folders and files and the result of the above method is
Second method
The second method is a bit more 'flat'. It is possible to create a CAML query to get all items from library recursively and then check if it's file or folder. All items have path property to determine the hierarchy.
private static void UseQueryToGetAllItems()
{
using (var context = new ClientContext(WebUrl))
{
context.Credentials = new SharePointOnlineCredentials(UserName, Password);
List<ListItem> result = new List<ListItem>();
try
{
ListItemCollectionPosition position = null;
int page = 1;
do
{
List list = context.Web.Lists.GetByTitle(LibName);
CamlQuery query = new CamlQuery();
query.ViewXml = new StringBuilder()
.Append("<View Scope=\"RecursiveAll\">")
.Append("<Query>")
.Append("")
.Append("</Query>")
.Append("<RowLimit>5000</RowLimit>")
.Append("</View>")
.ToString();
query.ListItemCollectionPosition = position;
ListItemCollection items = list.GetItems(query);
context.Load(items);
context.ExecuteQuery();
position = items.ListItemCollectionPosition;
if (items.Count > 0)
result.AddRange(items);
context.ExecuteQuery();
page++;
}
while (position != null);
result.ForEach(item =>
{
Console.WriteLine($"{item["ID"]}) Path: {item["FileDirRef"]} - Name: {item["FileLeafRef"]} - Type: {item.FileSystemObjectType}");
});
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadLine();
}
}
This method also does the authentication to the same library and then executes a query to get all the items to the list (the Query is done in a pagination way to overcome the threshold limit to get more than 5000 elements in query). After the method gets the list of all items it prints them out presenting the path, name of the file, and type (file or folder.. or other.. If remember well there might be also web and some other in this enum).
For the same library as the first method The result of this approach is
hope it helps :)
Related
For example, I have a folder called Effects, and there are tons of sub folders in it. I don't want to iterate files under Effects/Materials but others I want to iterate. How should I do that?
Please see below code:
class Program
{
static void Main(string[] args)
{
IterateItemsInFolder(#"C:\Users\MT\Desktop\Effects");
}
public static void IterateItemsInFolder(string path)
{
// We ignore Materials folder
if (Path.GetFileName(path) == "Materials") return;
// Get all files and directories in direcotry
var items = Directory.GetFileSystemEntries(path);
foreach(var item in items)
{
var attr = File.GetAttributes(item);
// If current item is directory, recurse.
if (attr.HasFlag(FileAttributes.Directory))
{
IterateItemsInFolder(item);
}
else
{
Console.WriteLine(item);
}
}
}
}
Skip Directories StartsWith or Contains or any other logic you want -
var directoryToSearch = #"C:\SearchDir\";
var directoryToExclude = #"C:\SearchDir\Exclude";
var files = (from f in Directory.GetFiles(directoryToSearch, "*.*", SearchOption.AllDirectories)
let directoryName = Path.GetDirectoryName(f)
where !directoryName.Contains(directoryToExclude)
select f).ToList();
return;
I'm browsing my instance, https://instance.sharepoint.com/1234/abc
That page contains a list of several folders and files. How do I download files from that path?
ClientContext cxt = new ClientContext(fullWebUrl);
cxt.Credentials = new SharePointOnlineCredentials(username, new NetworkCredential("", password).SecurePassword);
List list = cxt.Web.Lists.GetByTitle("Documents");
cxt.Load(list);
cxt.ExecuteQuery();
FolderCollection fcol = list.RootFolder.Folders;
List<string> lstFile = new List<string>();
foreach (Folder f in fcol)
{
if (f.Name == "filename")
{
cxt.Load(f.Files);
cxt.ExecuteQuery();
FileCollection fileCol = f.Files;
foreach (Microsoft.SharePoint.Client.File file in fileCol)
{
lstFile.Add(file.Name);
}
}
}
This fails down at the foreach with the error
Microsoft.SharePoint.Client.CollectionNotInitializedException: 'The collection has not been initialized
Would not cxt.ExecuteQuery do the job?
you can make a mass download from a SharePoint library without using code, just do the following:
1:go to your SharePoint Library
2:copy the full path
for example
https://sharepointdomain.com/sites/yoursite/yourLibraryName/forms/Allitems.aspx
now remove
/forms/allitems.aspx from the address and you will remain with
https://sharepointdomain.com/sites/yoursite/yourLibraryName
copy that and open your windows file browser and paste that in the address bar and your library will be opened as a local folder, then you can select all files and copy them to any destination even you can move them to another SharePoint library you might be prompted to enter your SharePoint credentials make sure to enter it is as follow:
username is : domain\your SharePoint user name
password : your SharePoint login password.
You need to load the FolderCollection fcol first (cxt.Load(fcol)):
List list = cxt.Web.Lists.GetByTitle("Documents");
cxt.Load(list);
cxt.ExecuteQuery();
FolderCollection fcol = list.RootFolder.Folders;
cxt.Load(fcol);
cxt.ExecuteQuery();
List<string> lstFile = new List<string>();
foreach (Folder f in fcol)
{
if (f.Name == "filename")
{
cxt.Load(f.Files);
cxt.ExecuteQuery();
FileCollection fileCol = f.Files;
foreach (Microsoft.SharePoint.Client.File file in fileCol)
{
lstFile.Add(file.Name);
}
}
}
To download the file:
foreach (Microsoft.SharePoint.Client.File file in fileCol)
{
var localstream = System.IO.File.Open("c:/" + file.Name, System.IO.FileMode.CreateNew);
var fileInfo = File.OpenBinaryDirect(cxt, file.ServerRelativeUrl);
var spstream = fileInfo.Stream;
spstream.CopyTo(localstream);
}
I tried to extract all my files and folders starting in c:\ to a tree data structure.
I get an UnAuthorized exception for some directories.
Is there another solution to check to see if I have permission to a folder?
I also tried using directoryName.Exists - it did not work.
my code:
private static void getAllFilesAndFoldersInPath(TreeView treeView, string path)
{
treeView.Items.Clear();
var stack = new Stack<TreeViewItem>();
var rootDirectory = new DirectoryInfo(path);
TreeViewItem node = new TreeViewItem();
node.Header = rootDirectory;
stack.Push(node);
while (stack.Count > 0)
{
var currentNode = stack.Pop();
var directoryInfo = (DirectoryInfo)currentNode.Header;
try
{
foreach (var directory in directoryInfo.GetDirectories())
{
if (!directory.Name.StartsWith("$"))
{
TreeViewItem childDirectoryNode = new TreeViewItem();
childDirectoryNode.Header = directory;
currentNode.Items.Add(childDirectoryNode);
stack.Push(childDirectoryNode);
}
}
foreach (var file in directoryInfo.GetFiles())
{
if (System.IO.Path.GetFileName(file.Name).StartsWith("~$") || System.IO.Path.GetExtension(file.Name) == ".tmp")
{
continue;
}
TreeViewItem tempNode = new TreeViewItem();
tempNode.Header = file;
currentNode.Items.Add(tempNode);
}
}
catch (UnauthorizedAccessException e) { }
}
treeView.Items.Add(node);
}
I would use EnumerateDirectories instead of GetDirectories. Much, much faster.
In your catch statement - do something with the exception. Don't just let the code swallow it, this is bad programming.
I have a handy little method I wrote awhile back that works well for me, feel free to give it a spin:
public IEnumerable<T> Find<T>(DirectoryInfo workingDirectory,
string searchPattern,
bool recursive = false)
where T : FileSystemInfo
{
var results = workingDirectory.EnumerateFileSystemInfos(searchPattern,
recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
return results.OfType<T>();
}
Where in your case you might call it like this:
var dirTree = Find<DirectoryInfo>(new DirectoryInfo("C:\\"), "*", true);
i want to display the all the files and sub folders from FTP using c#
how do i do?
can you one upload code?
i have tried import data from FTP in Tree view.but i cannot do
my code:
private TreeNode CreateDirectoryNode(string root, string p)
{
var directoryNode = new TreeNode("CGT");
var directoryListing = GetDirectoryListing(path);
var directories = directoryListing.Where(d => d.IsDirectory);
var files = directoryListing.Where(d => !d.IsDirectory);
foreach (var dir in directories)
{
directoryNode.Nodes.Add(CreateDirectoryNode(dir.FullPath, dir.Name));
}
foreach (var file in files)
{
directoryNode.Nodes.Add(new TreeNode(file.Name));
}
return directoryNode;
}
Leave this code this for example only..you people please help me out of here
I Need to find my pictures in my User folder. But I get the runtime error Access Denied
Here is my code
static void Main(string[] args)
{
string pic = "*.jpg";
string b = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
string appdata = Path.Combine(b, "AppData"); // I Dont want search in this folder.
string data = Path.Combine(b, "Data aplikací"); // Here also not.
foreach (string d in Directory.GetDirectories(b))
{
try
{
if ((d == data) || (d == appdata))
{
continue;
}
else
{
foreach (string f in Directory.GetFiles(d, pic))
{
//...
}
}
}
catch (System.Exception excpt)
{
Console.WriteLine(excpt.Message);
}
}
}
Running the application as admin doesn't work either. How to avoid this?
check if the folder is read only (in windows) if it is, just clear the read only flag.
if it isn't read only, make sure that the admin user has full rights on that folder. You can check this by right clicking on the folder --> properties --> security
check out this link for more information on how to set it programatically:
C# - Set Directory Permissions for All Users in Windows 7
Oh, don't go changing your directory/folder permissions - that's just asking for future pain.
There's no "one-liner" solution here - basically, you need to recursively walk through the folder structure looking for the files you care about, and absorbing/eating the UnauthorizedAccessExceptions along the way (you could avoid the exception altogether by checking DirectoryInfo.GetAccessControl, but that's a whole different question)
Here's a blob o'code:
void Main()
{
var profilePath = Environment
.GetFolderPath(Environment.SpecialFolder.UserProfile);
var imagePattern = "*.jpg";
var dontLookHere = new[]
{
"AppData", "SomeOtherFolder"
};
var results = new List<string>();
var searchStack = new Stack<string>();
searchStack.Push(profilePath);
while(searchStack.Count > 0)
{
var path = searchStack.Pop();
var folderName = new DirectoryInfo(path).Name;
if(dontLookHere.Any(verboten => folderName == verboten))
{
continue;
}
Console.WriteLine("Scanning path {0}", path);
try
{
var images = Directory.EnumerateFiles(
path,
imagePattern,
SearchOption.TopDirectoryOnly);
foreach(var image in images)
{
Console.WriteLine("Found an image! {0}", image);
results.Add(image);
}
var subpaths = Directory.EnumerateDirectories(
path,
"*.*",
SearchOption.TopDirectoryOnly);
foreach (var subpath in subpaths)
{
searchStack.Push(subpath);
}
}
catch(UnauthorizedAccessException nope)
{
Console.WriteLine("Can't access path: {0}", path);
}
}
}