On my FTP Server I have the following folder structure
- Parent Directory
-a.txt
-b.txt.old
-SubDirectory1
-c.txt
-NestedSubDirectory1
-d.txt
-SubDirectory2
-e.txt
-f.txt.old
The number of SDs are not fixed. I need a way to get all the files(can be any format) without the .old extension from the Parent Directory.
I'm currently using the 3rd party dll edtFTPnet.
ftpConnection.GetFileInfos()Where(f => !(f.Name.EndsWith(".old"))).ToList();
This helps me get the details of the files and folders at the current working directory level.
Can someone tell me a way to get all the files with the parentdirectory, subdirectories and nested subdirectories.
The solution may or may not use edtFTPnet.
FTPConnection.GetFileInfos() returns an array of FTPFile. The class FTPFile has a boolean property Dir which indicates whether its filename accesses a file (false) or directory (true).
Something like this should work:
void ReadSubDirectories(FTPConncetion connection, FTPFile[] files)
{
foreach (var file in files)
{
if (file.Dir)
{
// Save parent directory
var curDir = connection.ServerDirectory;
// Move into directory
connection.ChangeWorkingDirectory(file.Name)
// Read all files
ReadSubDirectories(connection, connection.GetFileInfos());
// Move back into parent directory
connection.ChangeWorkingDirectory(curDir)
}
else
{
// Do magic with your files
}
}
}
However you might be better off using just .NET's built-in FtpWebRequest class since its methods and naming conventions are clearer, it's better documented and it's easier to find references online.
Try to use extensions like this:
class Program
{
static void Main(string[] args)
{
using (var connection = new FTPConnection
{
ServerAddress = "127.0.0.1",
UserName = "Admin",
Password = "1",
})
{
connection.Connect();
connection.ServerDirectory = "/recursive_folder";
var resultRecursive =
connection.GetFileInfosRecursive().Where(f => !(f.Name.EndsWith(".old"))).ToList();
var resultDefault = connection.GetFileInfos().Where(f => !(f.Name.EndsWith(".old"))).ToList();
}
}
}
public static class FtpClientExtensions
{
public static FTPFile[] GetFileInfosRecursive(this FTPConnection connection)
{
var resultList = new List<FTPFile>();
var fileInfos = connection.GetFileInfos();
resultList.AddRange(fileInfos);
foreach (var fileInfo in fileInfos)
{
if (fileInfo.Dir)
{
connection.ServerDirectory = fileInfo.Path;
resultList.AddRange(connection.GetFileInfosRecursive());
}
}
return resultList.ToArray();
}
}
Related
I was tasked creating a small(?) utility that walks a directory tree level by level and creating each level by calling a CreateDir(folder, parent) function that I have no access to its source code and creates a directory if it finds its parent.
My question is similar to this question.
Assuming I have this structure
A
-B
--D
---G
--E
-C
--F
I should create A first, then B and C, then D,E, and F and then G.
Of course there is no limit to the depth.
I have created this method.
(IEnumerable<string>, IEnumerable<string>) GetAllFolders(string root)
{
var folders = Directory.EnumerateDirectories(root, "*", SearchOption.AllDirectories).Select(path => path.Replace(root, "").Substring(1));
var parents = folders.Select(path => path.Substring(0, (path.LastIndexOf(#"\") + 1) == 0 ? (path.LastIndexOf(#"\") + 1) : (path.LastIndexOf(#"\") ) ));
var listOfFolders = folders.ToList();
var listOfParents = parents.ToList();
return (listOfFolders, listOfParents);
}
And I try to create the structure using
foreach (var tuple in folders.Zip(parents, (x, y) => (x, y)))
{
if (tuple.y == String.Empty)
CreateDir(tuple.x,destination);
else
CreateDir(tuple.x, tuple.y);
}
where destination is a hardcoded path for the destination folder, folders and parents are the results of GetAllFolders.
I believe that I am overthinking it and that's why it is not working. Any simpler ideas?
Is this actually simpler? Not sure. Does it work? Yes. You could try a Linq.GroupBy query that ensures the list of source directories are sorted by depth and then combine this expression with a string.Replace that removes the source folder path, leaving only short names of all the directories it contains. By calling in order of depth, the parent is guaranteed to exist when the child folder is added.
This test routine uses a mock (shown at bottom) of the inaccessible CreateDirectory method you mention in your post.
static void Main(string[] args)
{
// The Copy-From source is mocked in the output directory.
var source = AppDomain.CurrentDomain.BaseDirectory;
// The Copy-To destination is mocked in local app data for this app
var destination = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"create_directories_by_depth"
);
// Making sure the list of directories is sorted by depth
var directoryLevels =
Directory
.GetDirectories(source, String.Empty, SearchOption.AllDirectories)
.Select(path=>path.Replace(source, String.Empty))
.GroupBy(path=>path.Split(Path.DirectorySeparatorChar).Length)
.OrderBy(group=>group.Key);
// Ensure that the top-level folder exists.
Directory.CreateDirectory(destination);
foreach (
var directoryLevel
in directoryLevels)
{
var shortPaths = directoryLevel.ToArray();
foreach (
var folder
in shortPaths.Select(shortPath=>Path.Combine(destination, shortPath)))
{
var parse = folder.Split(Path.DirectorySeparatorChar).ToList();
parse.Remove(parse.Last());
var parent = Path.Combine(parse.ToArray());
// MAKE THE CALL
CreateDirectory(folder, parent);
}
}
foreach (var directory in Directory.GetDirectories(destination, String.Empty, SearchOption.AllDirectories))
{
Console.WriteLine(directory);
}
Process.Start("explorer.exe", destination);
}
The inaccessible method:
// No access to source code
// Creates a directory if it finds its parent
private static void CreateDirectory(string folder, string parent)
{
if (Directory.Exists(parent))
{
Directory.CreateDirectory(folder);
}
else Debug.Assert(false, "Expecting to find existing parent!");
}
Here is the copied directory structure:
Is it possible to get only list of Excel filenames (like : 2021070701.CSV) in a folder ?
I'm getting the full path of the .csv excel when I use this "Directory.GetFiles" but I want to filter only excel filename with extension (like : 2021070701.CSV)
I used "FileInfo fi = new FileInfo();" but I didn't get the proper solution.
public static void getExcelFileName()
{
string[] filename = Directory.GetFiles(#"C:\Users\Ashok
Kumar\OneDrive\Desktop\Ashok\MarketPrice\NSE\Futures\Live", "*.csv");
foreach (var item in filename)
{
Console.WriteLine(item);
}
}
This is the path I'm getting
Help me out form this I'm new to coding.
You can use the GetFileNameWithoutExtension() method from the Path class to get the names of your files.
public static void getExcelFileName()
{
string[] filename = Directory.GetFiles(#"C:\Users\Ashok
Kumar\OneDrive\Desktop\Ashok\MarketPrice\NSE\Futures\Live", "*.csv");
foreach (var item in filename)
{
Console.WriteLine(Path.GetFileNameWithoutExtension(item));
}
}
Sure, you can call Path.GetFileName(string) which returns exactly what you're asking for!
public static void getExcelFileName()
{
string[] filesPaths = Directory.GetFiles(#"C:\Users\Ashok Kumar\OneDrive\Desktop\Ashok\MarketPrice\NSE\Futures\Live",
"*.csv");
foreach (var filePath in filesPaths)
{
Console.WriteLine(Path.GetFileName(filePath));
}
}
I am trying to create a microservice in C# which will accept a csv file containing order numbers, digest the csv, connect to sharepoint, create a new folder on sharepoint, and then copy contracts with names corresponding to the order number from whereever they may be (and they probably won't all be in the smae place) to the new folder.
At this point, with help from Stackoverflow, I can successfully get an authentication token from our Sharepoint using a CSOM Authentication Manager. And now I am trying to figure out how to create a the folder. Googling for information on creating Sharepoint folders keeps bringing up the topic of lists, which I don't know anything about and don't even know if I really want or need to know anything about, or whether there might be a different way which works with the site as that's what I'm actually interested in.
So, let's say I have a sharepoint site at https://example.sharepoint.com/sites/MySite.
How can I simply create a folder called "Foo" within a folder called "Bar" which exists in "Shared Documents"?
If I need to know something about lists in order to do this, can I use C# to find the correct list? Or do I need to chase my adminstrator for additional information?
Assuming the AuthenticationManager returns a valid context and the root folder already exists, the following works:
using Microsoft.SharePoint.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using AuthenticationManager = SharepointOrderContractExtractor.Clients.AuthenticationManager;
namespace SharePointOrderContractExtractor.Clients
{
public class FolderManager
{
private readonly AuthenticationManager _authenticationManager;
public FolderManager(
AuthenticationManager sharepointAuthenticationManager
)
{
_authenticationManager = sharepointAuthenticationManager;
}
internal Folder EnsureAndGetTargetFolder(string folderPath)
{
using ClientContext context = _authenticationManager.GetContext();
List<string> folderNames = folderPath.Split("/").ToList();
List documents = context.Web.Lists.GetByTitle(folderNames[0]);
folderNames.RemoveAt(0);
return EnsureAndGetTargetFolder(context, documents, folderNames);
}
private Folder EnsureAndGetTargetFolder(ClientContext context, List list, List<string> folderPath)
{
Folder returnFolder = list.RootFolder;
return (folderPath != null && folderPath.Count > 0)
? EnsureAndGetTargetSubfolder(context, list, folderPath)
: returnFolder;
}
private Folder EnsureAndGetTargetSubfolder(ClientContext context, List list, List<string> folderPath)
{
Web web = context.Web;
Folder currentFolder = list.RootFolder;
context.Load(web, t => t.Url);
context.Load(currentFolder);
context.ExecuteQuery();
foreach (string folderPointer in folderPath)
{
currentFolder = FindOrCreateFolder(context, list, currentFolder, folderPointer);
}
return currentFolder;
}
private Folder FindOrCreateFolder(ClientContext context, List list, Folder currentFolder, string folderPointer)
{
FolderCollection folders = currentFolder.Folders;
context.Load(folders);
context.ExecuteQuery();
foreach (Folder existingFolder in folders)
{
if (existingFolder.Name.Equals(folderPointer, StringComparison.InvariantCultureIgnoreCase))
{
return existingFolder;
}
}
return CreateFolder(context, list, currentFolder, folderPointer);
}
private Folder CreateFolder(ClientContext context, List list, Folder currentFolder, string folderPointer)
{
ListItemCreationInformation itemCreationInfo = new ListItemCreationInformation
{
UnderlyingObjectType = FileSystemObjectType.Folder,
LeafName = folderPointer,
FolderUrl = currentFolder.ServerRelativeUrl
};
ListItem folderItemCreated = list.AddItem(itemCreationInfo);
folderItemCreated.Update();
context.Load(folderItemCreated, f => f.Folder);
context.ExecuteQuery();
return folderItemCreated.Folder;
}
}
}
I´m working on a project that uses Caliburn micro in wpf C#.
I´m in the process that I want to rewrite my method ReadMediaFile() so it displays all files in a folder in a list.
My method looks lite this:
private void ReadMediaFile()
{
string result;
_movieviewmodel = new MoviesViewModel();
string[] filePaths = Directory.GetFiles(#"C:/Users/v80770/Desktop/Movies/");
foreach (var file in filePaths)
{
result = Path.GetFileName(file);
_movieviewmodel.MovieName = result;
}
AddItem(_movieviewmodel);
}
When I debug the program all the files show in filePaths but only one shows in my list.
The AddItem is located in a class called TreeViewBase (belongs to caliburn micro I think) and it looks like this:
public void AddItem(T item)
{
_dispatcher.SmartInvoke(() => Items.Add(item));
}
I got the movie files viewing in my list but my MediaUri binding in view is bind against a specific path file but I want it to change dependent on what I choose
I tried to edit the binding to this:
string test = _movieviewmodel.MovieName;
MediaUri = new Uri(test);
But only get a exception "System.UriFormatException: 'Invalid URI: The format of the URI could not be determined.'"
Picture of Uri
New Uri code:
_movieviewmodel.MovieFilePath = #"C:/Users/v80770/Desktop/Movies/";
string test = _movieviewmodel.MovieFilePath;
MediaUri = new Uri(test + _movieviewmodel.MovieName);
But it always shows the same movie and my _movieviewmodel.MovieName does not change name dependent which movie I choose, it always is the same movie.
The creation of a MoviesViewModel item object and AddItem(_movieviewmodel); must be inside foreach, otherwise it would add only the last item:
foreach (var file in filePaths)
{
var movieviewmodel = new MoviesViewModel();
movieviewmodel.MovieName = Path.GetFileName(file);
AddItem(movieviewmodel);
}
or
foreach (var file in filePaths)
{
AddItem(new MoviesViewModel
{
MovieName = Path.GetFileName(file)
});
}
Background: I'm using the HTML 5 Offline App Cache and dynamically building the manifest file. Basically, the manifest file needs to list each of the static files that your page will request. Works great when the files are actually static, but I'm using Bundling and Minification in System.Web.Optimization, so my files are not static.
When in the DEBUG symbol is loaded (i.e. debugging in VS) then the actual physical files are called from the MVC View. However, when in Release mode, it calls a virtual file that could look something like this: /bundles/scripts/jquery?v=FVs3ACwOLIVInrAl5sdzR2jrCDmVOWFbZMY6g6Q0ulE1
So my question: How can I get that URL in the code to add it to the offline app manifest?
I've tried:
var paths = new List<string>()
{
"~/bundles/styles/common",
"~/bundles/styles/common1024",
"~/bundles/styles/common768",
"~/bundles/styles/common480",
"~/bundles/styles/frontend",
"~/bundles/scripts/jquery",
"~/bundles/scripts/common",
"~/bundles/scripts/frontend"
};
var bundleTable = BundleTable.Bundles;
foreach (var bundle in bundleTable.Where(b => paths.Contains(b.Path)))
{
var bundleContext = new BundleContext(this.HttpContext, bundleTable, bundle.Path);
IEnumerable<BundleFile> files = bundle.GenerateBundleResponse(bundleContext).Files;
foreach (var file in files)
{
var filePath = file.IncludedVirtualPath.TrimStart(new[] { '~' });
sb.AppendFormat(formatFullDomain, filePath);
}
}
As well as replacing GenerateBundleResponse() with EnumerateFiles(), but it just always returns the original file paths.
I'm open to alternative implementation suggestions as well. Thanks.
UPDATE: (7/7/14 13:45)
As well as the answer below I also added this Bundles Registry class to keep a list of the required static files so that it works in debug mode in all browsers. (See comments below)
public class Registry
{
public bool Debug = false;
public Registry()
{
SetDebug();
}
[Conditional("DEBUG")]
private void SetDebug()
{
Debug = true;
}
public IEnumerable<string> CommonScripts
{
get
{
if (Debug)
{
return new string[]{
"/scripts/common/jquery.validate.js",
"/scripts/common/jquery.validate.unobtrusive.js",
"/scripts/common/knockout-3.1.0.debug.js",
"/scripts/common/jquery.timepicker.js",
"/scripts/common/datepicker.js",
"/scripts/common/utils.js",
"/scripts/common/jquery.minicolors.js",
"/scripts/common/chosen.jquery.custom.js"
};
}
else
{
return new string[]{
"/scripts/common/commonbundle.js"
};
}
}
}
}
I'm by no means happy with this solution. Please make suggestions if you can improve on this.
I can suggest an alternative from this blog post create your own token.
In summary the author suggests using web essentials to create the bundled file and then creating a razor helper to generate the token, in this case based on the last changed date and time.
public static class StaticFile
{
public static string Version(string rootRelativePath)
{
if (HttpRuntime.Cache[rootRelativePath] == null)
{
var absolutePath = HostingEnvironment.MapPath(rootRelativePath);
var lastChangedDateTime = File.GetLastWriteTime(absolutePath);
if (rootRelativePath.StartsWith("~"))
{
rootRelativePath = rootRelativePath.Substring(1);
}
var versionedUrl = rootRelativePath + "?v=" + lastChangedDateTime.Ticks;
HttpRuntime.Cache.Insert(rootRelativePath, versionedUrl, new CacheDependency(absolutePath));
}
return HttpRuntime.Cache[rootRelativePath] as string;
}
}
Then you can reference the bundled file like so...
#section scripts {
<script src="#StaticFile.Version("~/Scripts/app/myAppBundle.min.js")"></script>}
Then you have control of the token and can do what you want with it.