I followed a Microsoft example on how to access folders that were selected with a folder picker. After doing this I wanted to get all the paths of the sub folders within the selected top folder. I don't get any results however.
Code:
var folderPicker = new Windows.Storage.Pickers.FolderPicker();
folderPicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.Desktop;
folderPicker.FileTypeFilter.Add("*");
folderPicker.ViewMode = Windows.Storage.Pickers.PickerViewMode.List;
Windows.Storage.StorageFolder folder = await folderPicker.PickSingleFolderAsync();
if (folder != null)
{
Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.AddOrReplace("GameFilesToken", folder);
System.Diagnostics.Debug.WriteLine(folder.Path);
await FileManagementHelper.getFolders(folder.Path);
}
public static async Task<Queue<string>> getFolders(String TopLevel)
{
var Folder = await Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.GetFolderAsync("GameFilesToken");
var queryResults = Folder.CreateFolderQuery();
var folderList = await queryResults.GetFoldersAsync();
return new Queue<string>();
}
QueryResults gives me access to a folder, the same folder that I use originally.
FolderList gives me nothing.
FolderList gives me nothing.
Your getting folderList code snippet can work well, folderList object do has values if the selected folder have sub folders. Please update your getfolders method to check the folderList by code as follows:
var Folder = await Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.GetFolderAsync("GameFilesToken");
var queryResults = Folder.CreateFolderQuery();
var folderList = await queryResults.GetFoldersAsync();
foreach (StorageFolder folder in folderList )
{
Debug.WriteLine(folder.Path);
}
I wanted to get all the paths of the sub folders within the selected top folder. I don't get any results however.
Actually, you can just use StorageFolder.GetFoldersAsync() method to get all sub folders for the selected top folder object, there is no need to use CreateFolderQuery() method if you want to list all. Code as follows:
private async void btngetfolder_Click(object sender, RoutedEventArgs e)
{
var folderPicker = new Windows.Storage.Pickers.FolderPicker();
folderPicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.Desktop;
folderPicker.FileTypeFilter.Add("*");
folderPicker.ViewMode = Windows.Storage.Pickers.PickerViewMode.List;
Windows.Storage.StorageFolder folder = await folderPicker.PickSingleFolderAsync();
if (folder != null)
{
IReadOnlyList<StorageFolder> folderList = await folder.GetFoldersAsync();
foreach (StorageFolder subfolder in folderList)
{
Debug.WriteLine("subfolder path:" + subfolder.Path);
}
}
}
More details please reference the FolderEnumeration official sample.
Update:
If you want to get all sub folders include descendants sub folders, you need to set QueryOptions.FolderDepth to deep. Code as follows:
var Folder = await Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.GetFolderAsync("GameFilesToken");
QueryOptions options = new QueryOptions();
options.FolderDepth = FolderDepth.Deep;
var queryResults = Folder.CreateFolderQueryWithOptions(options);
var folderList = await queryResults.GetFoldersAsync();
foreach (StorageFolder folder in folderList )
{
Debug.WriteLine(folder.Path);
}
Related
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 :)
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 have folders and files on the "koleksibuku" folder on carousel. I want to be when moveBtn clicked, it will display a list of names of available folders (including root folder). How do I display a list of available folders in the "koleksibuku" folder?
Code to display files and folders on gridview:
loading.IsIndeterminate = true;
StorageFolder koleksibuku = await installedLocation.CreateFolderAsync("koleksibuku", CreationCollisionOption.OpenIfExists);
ObservableCollection<Book> datasource = new ObservableCollection<Book>();
IReadOnlyList<StorageFile> files = await koleksibuku.GetFilesAsync();
IReadOnlyList<StorageFolder> folders = await koleksibuku.GetFoldersAsync();
StorageFolder thumbfolder = await installedLocation.CreateFolderAsync("thumb", CreationCollisionOption.OpenIfExists);
files = await koleksibuku.GetFilesAsync();
folders = await koleksibuku.GetFoldersAsync();
foreach (StorageFile file in files)
{
Book buku = new Book();
buku.Name = file.DisplayName.ToString();
if ((isbukudownloading(file.Name.ToString())) && (file.Name.ToString() != DownloadFileName))
{
}
else
{
StorageFile thumbFile;
StorageFolder thumbFolder;
bool bukuada = true;
try
{
var folder1 = await installedLocation.GetFolderAsync("kolesibuku");
thumbFile = await thumbfolder.GetFileAsync(file.Name.ToString() + ".png");
BitmapImage bi = new BitmapImage();
bi.SetSource(await thumbFile.OpenAsync(FileAccessMode.Read));
buku.Image = bi;
datasource.Add(buku);
}
catch
{
bukuada = false;
}
if (!bukuada)
{
loading.IsIndeterminate = true;
var task = Task.Run(async () => { await RenderCoverBuku(file.Name.ToString(), 0); });
task.Wait();
thumbFile = await thumbfolder.GetFileAsync(file.Name.ToString() + ".png");
BitmapImage bi = new BitmapImage();
bi.SetSource(await thumbFile.OpenAsync(FileAccessMode.Read));
buku.Image = bi;
datasource.Add(buku);
}
}
}
foreach (StorageFolder folder in folders)
{
Book buku = new Book();
buku.Name = folder.DisplayName.ToString();
BitmapImage folderImage = new BitmapImage(new Uri("ms-appx:///images/folders_png8761.png"));
buku.Image = folderImage;
datasource.Add(buku);
}
this.carousel.ItemsSource = datasource;
this.carousel.SelectedItem = carousel.Items[0];
loading.IsIndeterminate = false;
}
private void moveBtn_Click(object sender, RoutedEventArgs e)
{
}
Note:
The name of the folder created by the user as desired user
This is how I was creating a folder on OneDrive using Windows Phone API.
public async Task<string> CreateSkyDriveFolder()
{
string folderId = null;
var opResult = await Client.GetAsync("me/skydrive/files?filter=folders");
dynamic result = opResult.Result;
foreach (dynamic folder in result.data)
{
if (folder.name.ToLowerInvariant().Trim() == skyDriveFolderName.ToLowerInvariant().Trim())
{
folderId = folder.id;
break;
}
}
if (folderId == null)
{
var folderData = new Dictionary<string, object>();
folderData.Add("name", skyDriveFolderName);
opResult = await Client.PostAsync("me/skydrive", folderData);
result = opResult.Result;
folderId = result.id;
}
}
But now, I just want to replace a folder name 'OldFolder' on OneDrive to 'NewFolder'. How can I do this using API?
Any help will much be appreciated. Thanks. :-)
Each folder in the OneDrive API is considered to be an "item".
And each item can be updated with a new name.
These rows should update the item with id "folderId" and give it the new name "NewFolder".
var Client = new HttpClient();
var request = new HttpRequestMessage(
new HttpMethod("PATCH"),
String.Format("/drive/items/{0}", folderId)
);
var renameInstruction = new StringContent("{\"name\":\"NewFolder\"}");
request.Content = renameInstruction;
var opResult = await Client.SendAsync(request);
Tested on my private OneDrive folder using the OneDrive console.
API source: https://github.com/OneDrive/onedrive-api-docs/blob/master/items/update.md
Let me know if anything is unclear or strange in any way. Have a marvelous day!
I'm dealing with unzipping zip file with some hierarchy of files to Local folder. I tried ZipArchive but extension method ExtractToDirectory is not supported on winrt. Some other possibilities are DotNetZip and SharpZipLib but these libraries are not supported on winrt too.
Zip hierarchy file can look like this (I assume depth of the hierarchy max 2):
folder1/picture1.jpg
folder1/picture2.jpg
folder2/picture1.jpg
folder2/picture2.jpg
Some simplified code sample :
var data = await client.GetByteArrayAsync("..../file.zip");
var folder = Windows.Storage.ApplicationData.Current.LocalFolder;
var option = Windows.Storage.CreationCollisionOption.ReplaceExisting;
var file = await folder.CreateFileAsync("file.zip", option);
Windows.Storage.FileIO.WriteBytesAsync(file, data);
// zip is saved to Local folder and now I need extract files hierarchy from this zip
Do you have some clever and simple solution for this issue? Do you know some useful library, nuget package for winrt or Portable class library?
Some extension methods I have to handle this stuff using ZipArchive.
public static async Task<IStorageItem> CreatePath(this StorageFolder folder, string fileLocation, CreationCollisionOption fileCollisionOption, CreationCollisionOption folderCollisionOption)
{
var localFilePath = PathHelper.ToLocalPath(fileLocation).Replace(PathHelper.ToLocalPath(folder.Path), "");
if (localFilePath.Length > 0 && (localFilePath[0] == '/' || localFilePath[0] == '\\'))
{
localFilePath = localFilePath.Remove(0, 1);
}
if (localFilePath.Length == 0)
{
return folder;
}
var separatorIndex = localFilePath.IndexOfAny(new char[] { '/', '\\' });
if (separatorIndex == -1)
{
return await folder.CreateFileAsync(localFilePath, fileCollisionOption);
}
else
{
var folderName = localFilePath.Substring(0, separatorIndex);
var subFolder = await folder.CreateFolderAsync(folderName, folderCollisionOption);
return await subFolder.CreatePath(fileLocation.Substring(separatorIndex + 1), fileCollisionOption, folderCollisionOption);
}
}
public static async Task ExtractToFolderAsync(this ZipArchive archive, StorageFolder folder)
{
foreach (var entry in archive.Entries)
{
var storageItem = await folder.CreatePathAsync(entry.FullName, CreationCollisionOption.OpenIfExists, CreationCollisionOption.OpenIfExists);
StorageFile file;
if ((file = storageItem as StorageFile) != null)
{
using (var fileStream = await file.OpenStreamForWriteAsync())
{
using (var entryStream = entry.Open())
{
await entryStream.CopyToAsync(fileStream);
}
}
}
}
}