Export Visual Studio folder structure into Excel - c#

Is there a way to export Visual Studio "Solution Explorer" structure into excel?
I tried "tree" command and clip it via Windows Command Prompt like this:
but it's little hard to splite to each Excel sells.
I expecting result like this:
so any good idea for it?
Thanks.

Here you have a solution. Preety simple recursive solution to list files in the format you want
public class GetFilesTreeList
{
private static List<Files> files = new List<Files>();
public static void Main(string[] args)
{
var path = #"C:\Users\Lukasz\Desktop";
files.Add(new Files(Path.GetFileName(path), 0));
WriteFilesRec(path, 1);
foreach (var filese in files)
{
Console.WriteLine(filese);
}
}
public class Files {
public int column;
public string name;
public Files(string name, int column)
{
this.column = column;
this.name = name;
}
public override string ToString()
{
return new String('+', column) + name;
}
}
public static void WriteFilesRec(string path, int i) {
DirectoryInfo directory = new DirectoryInfo(path);
foreach(var d in directory.GetDirectories()) {
files.Add(new Files(d.Name, i));
WriteFilesRec(Path.Combine(path, d.Name), i+1);
}
foreach(var f in directory.GetFiles()) {
files.Add(new Files(f.Name, i));
}
}
}

Related

How do I Write Error saved in a Logger in my Console in C#

If I have my class
public class File
{
public bool Load(string fileName)
bool returnValue = false;
if (File.Exists(fileName))
{
returnValue = true;
Logger.Info("File found.");
}
else
{
Logger.Error("File does not exists.");
}
return returnValue;
}
I tried in my main Program.cs
class Program
{
static void Main(string[] args)
{
var appender = new log4net.Appender.MemoryAppender();
log4net.Config.BasicConfigurator.Configure(appender);
var logEntries = appender.GetEvents();
File file = new File();
string folderPath = #"C:\User\files\";
string[] files = Directory.GetFiles(folderPath, "*.*", SearchOption.AllDirectories);
foreach(string oneFile in files)
{
file.Load(oneFile);
Console.WriteLine(logEntries);
}
Console.ReadLine();
}
}
My program does not write any log in the console, any one can explain why ?
Maybe I am all wrong. I just don't get it.

How to prevent recursive in copying files and dirs?

I bumped into the problem with copying files/dirs. Been struggling almost for whole day.
I have to copy from root dir files and its dires with files and subdirs.
Actually, i've made something. However, every time i run in the stackoverflow error.
abstract class SystemOperations {
public virtual void SearchFiles() { }
public virtual void SearchDirectories() { }
public abstract void CreateDirectory(string DIR);
public abstract void CloneContent(string DIR);
public abstract void CreateJSON(string DIR);
public void ExecuteCopying(string DIR) {
CreateDirectory(DIR);
CloneContent(DIR);
CreateJSON(DIR);
}
}
class FileOperations : SystemOperations {
DirectoryInfo _MainPath;
public DirectoryInfo MainPath {
get { return _MainPath; }
set { _MainPath = value; }
}
public FileOperations(DirectoryInfo MainPath) {
this.MainPath = MainPath;
}
#region Unnecessary for current task
public override void SearchFiles() {
string path = "";
FileInfo[] files = MainPath.GetFiles();
foreach (FileInfo file in files) {
path = file.Name;
}
}
public override void SearchDirectories() {
string path = "";
DirectoryInfo[] directories = MainPath.GetDirectories();
foreach (DirectoryInfo directory in directories) {
path = directory.Name;
}
}
#endregion
public override void CreateDirectory(string DIR) {
string newFolder = Path.Combine(MainPath + "", DIR);
Directory.CreateDirectory(newFolder);
}
public override void CloneContent(string DIR) {
foreach (var directory in Directory.GetDirectories(MainPath + "")) {
string dir = Path.GetFileName(directory);
CloneContent(Path.Combine(MainPath + "", dir));
}
foreach (var file in Directory.GetFiles(MainPath + "")) {
File.Copy(file, Path.Combine(MainPath + "", Path.GetFileName(file)), true);
}
}
public override void CreateJSON(string DIR) {
if (!Directory.Exists(DIR)) {
var asd = new DirectoryInfo(DIR);
}
}
}
class Program {
static void Main() {
SystemOperations task = new FileOperations(new DirectoryInfo(#"D:\\LAK"));
task.ExecuteCopying("COPY");
}
}
So, the function CloneContent has to copy in each dir/subdirs files. But its recursive func and as i written above, i run to the error. And dont know how to fix this one. Thank u!
There is some kind of problem with the way you are trying to determine which directory you need to search next, the use of MainPath looks wrong to me.
Personally i also always prefer to have a secondary stop condition to avoid a StackOverflowException, like the maxrunCount i use below.
If you want a recursive directory lookup you should rewrite your code to something like
void Main()
{
string MainPath = "D:\\LAK";
// unless your directory is actually named \LAK:) you should use either #"D:\LAK" or "d:\\LAK"
CloneContent(MainPath,1000);
}
public void CloneContent(string directoryToSearch, int maxrunCount)
{
if(maxrunCount==0)
return;
System.Diagnostics.Debug.Print(directoryToSearch);
string[] directories = null;
try
{
directories = Directory.GetDirectories(directoryToSearch);
}
catch(UnauthorizedAccessException ex) {
System.Diagnostics.Debug.Print($"No access to dir {directoryToSearch}");
directories = new string[0];
}
// ensure you have access to the current directoryToSearch
foreach (var directory in directories)
{
CloneContent(directory,--maxrunCount);
}
System.Diagnostics.Debug.Print($"cloning {directoryToSearch}");
// .... do the actual cloning here,
// you will end up here when there are no more subdirectories on the current branch
}
For a recursive method to work, it must have at least one "exit" condition - the point at which it's done its job and can unwind the stack. In our case, it would be when there are no more direcories or files to copy from the source to the destination.
One way of writing this method would take in a source directory and a destination directory, and then it can recursively call itself for each sub-directory:
public static void CloneContent(string sourceDir, string destDir)
{
// If the source directory doesn't exist, return
if (!Directory.Exists(sourceDir)) return;
// Create destination if needed
Directory.CreateDirectory(destDir);
// Copy files from this directory to the new path
foreach (string file in Directory.GetFiles(sourceDir))
{
File.Copy(file, Path.Combine(destDir, Path.GetFileName(file)));
}
// Recursively call this method for each sub directory
foreach (string subDir in Directory.GetDirectories(sourceDir))
{
string dirName = Path.GetFileName(subDir);
string newSource = Path.Combine(sourceDir, dirName);
string newDest = Path.Combine(destDir, dirName);
CloneContent(newSource, newDest);
}
}

Sequential file name in NLog

I would like my file name to be changed dynamically and include a sequence number. The file name should be changed (increment the number) at each archiving process/log rotation.
When archiving the file, the archive file name should be the same as the file name with the sequence number (before the increment).
Starting with file name to be 'file.log.1', when archiving the archive file name will be 'file.log.1' and the file name will be changed to 'file.log.2'.
The next archive file name will be 'file.log.2' and so on...
Is it possible using NLog?
Didn't find any clue in the web or the NLog source code.
So I implemented a custom FileTarget that answer my needs:
internal sealed class CustomFileTarget : NLog.Targets.FileTarget
{
private const int _maxOldFilesToKeep = 10;
private readonly string _directory;
private readonly long _fileMaxSize = (long)10.Megabytes().Bytes;
private readonly string _fileNamePrefix;
private int _sequential;
private string FullFileName => $"{Path.Combine(_directory, _fileNamePrefix)}.{_sequential}.log";
public CustomFileTarget(string directory, string fileNamePrefix)
{
_directory = directory;
_fileNamePrefix = fileNamePrefix;
_sequential = GetLatestSequence() ?? 0;
ConcurrentWrites = false;
FileName = FullFileName;
KeepFileOpen = false;
}
protected override void Write(IList<AsyncLogEventInfo> logEvents)
{
base.Write(logEvents);
if (GetFileSize() >= _fileMaxSize)
{
ChangeName();
DeleteOld();
}
}
private long GetFileSize() =>
new FileInfo(FullFileName).Length;
private void ChangeName()
{
_sequential++;
FileName = FullFileName;
LogManager.ReconfigExistingLoggers();
}
private void DeleteOld()
{
var fileNamesAndSequences = GetFileNamesAndSequences();
if (fileNamesAndSequences.Count() > _maxOldFilesToKeep + 1)
{
fileNamesAndSequences.Take(
fileNamesAndSequences.Count() - _maxOldFilesToKeep + 1)
.ForEach(
_ => Directory.Delete(Path.Combine(_directory, _.FileName)));
}
}
private int? GetLatestSequence()
{
var fileNamesAndSequences = GetFileNamesAndSequences();
return fileNamesAndSequences.Any()
? fileNamesAndSequences.Last().Sequence
: (int?)null;
}
private IEnumerable<(string FileName, int Sequence)> GetFileNamesAndSequences() =>
Directory.GetFiles(_directory, $"{_fileNamePrefix}*.log").
Select(
_ =>
{
var fileNameParts = _.Split('.');
return (_, Sequence: int.Parse(fileNameParts[fileNameParts.Length - 2]));
}).
OrderBy(_ => _.Sequence);
}

How do you programmatically get the file name when dragging and dropping from .Net Solution explorer?

I want to write an application that produces zip files by directly dragging and dropping files from Visual Studio Solution Explorer into my app.
I've used the following code snippet to catch the incoming DataObject:
private void lblIncludedFiles_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Copy;
}
}
I've tried every possible value of DataFormats, all of them return false.
Since this task might be somewhat less simple than it looks like on paper, here's a sample procedure that should allow to get a list of the files dragged from the Visual Studio Solution Explorer panel.
The DataFormats that Visual Studio generates are partially common (UnicodeText and Text), but the actual file list is passed on in a (classic) MemoryStream object that is not a common DataFormat: CF_VSSTGPROJECTITEMS.
The MemoryStream contains Unicode text - the actual list of the Project+File Name tuples that are being dropped - separated by a pipe (|) symbol - and some other binary sections that I don't think is useful to describe here.
The other non common/predefined format, VX Clipboard Descriptor Format, is also a MemoryStream object, but it's just an Unicode string that contains the Project name.
In this sample, the combined elements that are part of the Drop are organized using a custom class object that contains informations about:
the name and UUID of the Project(s) where the files are coming from,
the Project path and file path (.[xxx]prj) ,
the name of the object that started the Drag&Drop operation,
a list of all files that are dropped, the Project they're part of and their raw type (.cs, .vb, .h, .png etc.)
Pick a control that will receive the Drop and add the handlers:
private void ctlVSDrop_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetFormats().Contains("CF_VSSTGPROJECTITEMS"))
{
e.Effect = DragDropEffects.Copy;
}
}
private void ctlVSDrop_DragDrop(object sender, DragEventArgs e)
{
var vsObject = new VisualStudioDataObject(e.Data);
}
The class object, VisualStudioDataObject, contains the methods needed to extract the informations from the DataObject referenced by the DragDrop event DragEventArgs:
(Tested with Visual Studio 2017)
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
class VisualStudioDataObject
{
public VisualStudioDataObject(IDataObject data)
{
if (data is null) {
throw new ArgumentNullException("IDataObject data", "Invalid DataObject");
}
FileList = new List<FileObject>();
GetData(data);
}
public List<FileObject> FileList { get; private set; }
public string ProjectUUID { get; private set; }
public string ProjectPath { get; private set; }
public string ProjectFilePath { get; private set; }
public string StartingObject { get; private set; }
public class FileObject
{
public FileObject(string project, string path, string type) {
SourceProject = project;
FilePath = path;
FileType = type;
}
public string SourceProject { get; }
public string FilePath { get; }
public string FileType { get; }
}
private void GetData(IDataObject data)
{
List<string> formats = data.GetFormats(false).ToList();
if (formats.Count == 0) return;
foreach (string format in formats) {
switch (format) {
case "UnicodeText":
StartingObject = data.GetData(DataFormats.UnicodeText, true).ToString();
break;
case "VX Clipboard Descriptor Format":
var projectMS = (MemoryStream)data.GetData(format, false);
projectMS.Position = 0;
string prjFile = Encoding.Unicode.GetString(projectMS.ToArray()).TrimEnd("\0".ToCharArray());
ProjectFilePath = prjFile;
ProjectPath = Path.GetDirectoryName(prjFile);
break;
case "CF_VSSTGPROJECTITEMS":
GetFileData((MemoryStream)data.GetData(format, false));
break;
}
}
}
private void GetFileData(MemoryStream ms)
{
string uuidPattern = #"\{(.*?)\}";
string content = Encoding.Unicode.GetString(ms.ToArray());
//Get the Project UUID and remove it from the data object
var match = Regex.Match(content, uuidPattern, RegexOptions.Singleline);
if (match.Success) {
ProjectUUID = match.Value;
content = content.Replace(ProjectUUID, "").Substring(match.Index);
//Split the file list: Part1 => Project Name, Part2 => File name
string[] projectFiles = content.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < projectFiles.Length; i += 2) {
string sourceFile = projectFiles[i + 1].Substring(0, projectFiles[i + 1].IndexOf("\0"));
FileList.Add(new FileObject(projectFiles[i], sourceFile, Path.GetExtension(sourceFile)));
}
}
else {
FileList = null;
throw new InvalidDataException("Invalid Data content");
}
}
}
I try you approch out with a TreeView Control:
Tree.AllowDrop = true;
Tree.DragEnter += (s, e) =>
{
e.Effect = DragDropEffects.Move;
};
Tree.DragDrop += (s, e) =>
{
var data = e.Data;
var value = data.GetData(typeof(string));
};
After drop a cs-File from the solution explorer inside the tree, you can read out the path of the cs-File. The path you can use to convert the file to zip.
>>> value = "C:\\Users\\Name\\Desktop\\Projekte\\Projekte-Visual Studio\\Project\\Project\\Classes\\Method.cs"
Hope it helps.

How to use Microsoft.Build.Evaluation.Project.RemoveItem

I've successfuly added files programatically to my project using the following code:
var project = new Microsoft.Build.Evaluation.Project(projPath);
project.AddItem("Compile", filePath);
However, removing a file programatically is giving me a hard time.
Signature:
public bool RemoveItem(
ProjectItem item
)
How can I instantiate a ProjectItem? I couldn't find any examples.
Reference: https://msdn.microsoft.com/en-us/library/microsoft.build.evaluation.project.removeitem.aspx
you did
private static ProjectItem GetProjectItem(this Project project, string filePath)
{
var includePath = filePath.Substring(project.DirectoryPath.Length + 1);
var projectItem = project.GetItems(CompileType).FirstOrDefault(item => item.EvaluatedInclude.Equals(includePath));
return projectItem;
}
in your GetProjectItem method:
replace that:
var projectItem = project.GetItems(CompileType).FirstOrDefault(item => item.EvaluatedInclude.Equals(includePath));
with this:
var projectItem = project.GetItems("Compile").ToList()
.Where(item => item.EvaluatedInclude.Equals(includePath)).FirstOrDefault();
using .FirstOrDefault() will bring it to have just first item of all files. i used .ToList() and made it work with all my items which have same EvaluatedInclude. its totally worked for my.
This is the class I ended up writing. No simple solution for remove.
public static class SourceControlHelper
{
public static void CheckoutFile(string filePath)
{
TFSAction((workspace) => workspace.PendEdit(filePath), filePath);
}
public static void AddFile(this Project project, string filePath)
{
CheckoutFile(project.FullPath);
var projectItem = project.GetProjectItem(filePath);
if (projectItem != null)
{
return;
}
var includePath = filePath.Substring(project.DirectoryPath.Length + 1);
project.AddItem(CompileType, includePath);
project.Save();
TFSAction(workspace => workspace.PendAdd(filePath), filePath);
}
public static void DeleteFile(this Project project, string filePath)
{
CheckoutFile(project.FullPath);
var projectItem = project.GetProjectItem(filePath);
if (projectItem == null)
{
return;
}
project.RemoveItem(projectItem);
project.Save();
TFSAction(workspace => workspace.PendDelete(filePath), filePath);
}
private static ProjectItem GetProjectItem(this Project project, string filePath)
{
var includePath = filePath.Substring(project.DirectoryPath.Length + 1);
var projectItem = project.GetItems(CompileType).FirstOrDefault(item => item.EvaluatedInclude.Equals(includePath));
return projectItem;
}
private static void TFSAction(Action<Workspace> action, string filePath)
{
var workspaceInfo = Workstation.Current.GetLocalWorkspaceInfo(filePath);
if (workspaceInfo == null)
{
Console.WriteLine("Failed to initialize workspace info");
return;
}
using (var server = new TfsTeamProjectCollection(workspaceInfo.ServerUri))
{
var workspace = workspaceInfo.GetWorkspace(server);
action(workspace);
}
}
private static string CompileType
{
get { return CopyTool.Extension.Equals("ts") ? "TypeScriptCompile" : "Compile"; }
}
}

Categories