In C#,
I want directory names list.
Type is List and I have full pah list(List fullPathList).
fullpathList is like this..
[0] C:\temp\image\a.jpg;
[1] C:\temp\image\b.bmp;
[2] c:\temp\bin\my.exe;
[3] c:\temp\document\resume.doc;
[4] c:\temp\document\timetable.xlsx;
In this case,
I want it.
List<string> dirs;
[0] iamge
[1] bin
[2] document
I guess possible if i using Regx.
But, i dont know detailed method.
how can I do for it?
(dont use loop statement)
I believe this prints what you want...
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
namespace Test {
class Program {
static void Main(string[] args) {
var files = new string[] {
#"C:\temp\image\a.jpg",
#"C:\temp\image\b.bmp",
#"c:\temp\bin\my.exe",
#"c:\temp\document\resume.doc",
#"c:\temp\document\timetable.xlsx",
};
var dirNames = files.Select(x => new DirectoryInfo(Path.GetDirectoryName(x)).Name);
Debug.WriteLine($"dirNames={string.Join(",", dirNames)}");
}
}
}
The Path.GetDirectoryName() returns the full path and new DirectoryInfo().Name returns just the name of the last part of the path.
If you want the result in a list, use...
var dirNames = files.Select(x => new DirectoryInfo(Path.GetDirectoryName(x)).Name).ToList();
Check if this solution Works.
it gets all the directory in the specified drive.
Please go through the reference link ref link
List<string> dir = new List<string>();
System.IO.DriveInfo di = new System.IO.DriveInfo(#"D:\");
System.IO.DirectoryInfo dirInfo = di.RootDirectory;
System.IO.DirectoryInfo[] dirInfos = dirInfo.GetDirectories("*.*");
foreach (System.IO.DirectoryInfo d in dirInfos)
{
dir.Add(d.Name);
}
For a real filesystem DirectoryInfo is the way to go.
If you do not have a real filesystem to query, but have a list of strings that are like paths you can use System.IO.Path - Static methods to split them up like this:
using System;
using System.Linq;
using System.IO;
public class Program
{
public static void Main()
{
// some strings that are like paths
var dirs = new[]
{
#"C:\temp\image\a.jpg", #"C:\temp\image\b.bmp", #"c:\temp\bin\my.exe",
#"c:\temp\document\resume.doc", #"c:\temp\document\timetable.xlsx"
};
// this will use a static method to extract only the path-part
var fullDirs = dirs.Select(d => Path.GetDirectoryName(d)).ToList();
// this will use the same method but split the result at the default systems
// path-seperator char and use only the last part, only uses distinct values
var lastDirsDistinct = dirs.Select(d => Path.GetDirectoryName(d)
.Split(Path.DirectorySeparatorChar).Last()
).Distinct().ToList();
// joins the list with linebreaks and outputs it
Console.WriteLine(string.Join("\n", fullDirs));
// joins the list with linebreaks and outputs it
Console.WriteLine(string.Join("\n", lastDirsDistinct ));
}
}
Output:
C:\temp\image
C:\temp\image
c:\temp\bin
c:\temp\document
c:\temp\document
image
bin
document
Related
I have a set of folders containing log files. Each folder is named as the date the log files were created. I am getting the content of these folders within X days of today and storing the resulting FileInfo in a list. So it is possible to have file info with same file name X times, or less.
I need to keep only the latest files based on create date. So, if the list contains multiple entries where fi.FileName is the same, I need to keep the latest, based on fi.CreateDate and ditch the other instance(s).
I tried something like this but am messing up somewhere:
files = files.GroupBy(i => new {i.FileName, i.CreateDate}).Select(i => i.Last()).ToList();
You must change your sort code as follows:
files = files.OrderBy(f=>f.CreateDate).GroupBy(i => i.FileName).Select(i => i.Last()).ToList();
This one also will give the same result:
files =files.GroupBy(i => i.FileName).Select(i => i.OrderByDescending(f=>f.CreateDate).First()).ToList();
You can use such a method to get files to purge:
using System.IO;
using System.Linq;
using System.Collections.Generic;
static public IEnumerable<FileInfo> GetTraceFiles(bool sortByDateOnly = true)
{
string folder = "MyFullPath"; // Can be from some instance
string prefix = "MyTraceFile-"; // global vars
string extension = ".log"; // and config
var list = Directory.GetFiles(folder, prefix + "*" + extension)
.Where(f => !IsFileLocked(f))
.Select(f => new FileInfo(f))
.OrderBy(fi => fi.CreationTime);
return sortByDateOnly ? list : list.ThenBy(fi => fi.FullName);
}
And this clear method:
static public void ClearTraces(int retain = 0)
{
var list = GetTraceFiles();
if ( retain > 0 ) list = list.Take(list.Count() - retain + 1);
foreach ( var fileInfo in list )
try
{
File.Delete(fileInfo.FullName);
}
catch
{
}
}
Here it retains retain last files but you can adapt to add a Where clause to use a date before which to erase:
.Where(fi => fi.CreationTime < ...);
Also instead of using the file system creation date and time, it is possible to use the file pattern in case for example MyTrace-YYYY-MM-DD#HH-MM-SS...
IsFileLocked comes from:
Is there a way to check if a file is in use?
Whenever I run this code, it returns one character. I've tried various things, and at most it returns 5 or so lines, each containing one character. I'm trying to find each folder in the "Users" folder, and make my code list them, any help would be appreciated.
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
//Search for directories and foreach, try to start discord
try
{
var Bruhm = new List<string>();
Bruhm.Add(Directory.GetDirectories(#"C:\Users\").ToString());
int y = 0;
foreach (string x in Bruhm) {
Console.WriteLine(x[y]);
y = y+1;
}
}
catch(Exception e)
{
Console.WriteLine(e);
System.Threading.Thread.Sleep(-1);
}
System.Threading.Thread.Sleep(-1);
}
}
}
The first mistake you are making is;
Bruhm.Add(Directory.GetDirectories(#"C:\Users\").ToString());
will add only one string, which is System.String[] to your list.
The second mistake is, x[y] will print only one character, which is the character at y index inside the string x.
Change the Add() to AddRange(), and do not call ToString() on your list.
Try this:
var Bruhm = new List<string>();
Bruhm.AddRange(Directory.GetDirectories(#"C:\Users\"));
foreach (string x in Bruhm)
{
Console.WriteLine(x);
}
It's quite simple. You're doing error with this: Directory.GetDirectories(#"C:\Users\").ToString()
Instead try this:
var Bruhm = Directory.GetDirectories(#"C:\Users\");
foreach(var subdir in Bruhm)
Console.WriteLine(subDir);
You are converting a list into a string and printing an index of it and it makes wrong result. You can extract the folder name using this code. "C:\Users\" has removed from the folder's path to provide folders' name not path.
var path = #"C:\Users\";
var Bruhm = Directory.GetDirectories(path).Select(x => x.Substring(path.Length));
foreach (string x in Bruhm)
{
Console.WriteLine(x);
}
I have a list(in txt file) that looks like this field:description
field20D.name = Reference
field20[101].name = Sender's Reference
field20[102].name = File Reference
field20[102_STP].name = File Reference
field20[103].name = Sender's Reference
The numbers in [] like 101,102 are messagetype.
How can i write the code so when i have a property with any value in that list, to get the equivalent description for it.
example: when a field has a value "20D" to build a string "20D - Reference"
Here's a good class that can do what you stated above.
using System;
using System.Collections.Generic;
namespace TestConsoleProject
{
public class WeirdLineFormatReader
{
public IEnumerable<Tuple<string, string>> ReadLines(IEnumerable<string> lines)
{
foreach (string line in lines)
{
// split each line on the =
string[] strLineArray = line.Split('=');
// get the first and second values of the split line
string field = strLineArray[0];
string value = strLineArray[1];
// remove the first field word
field = field.Substring("field".Length);
// remove the .name portion
field = field.Replace(".name", "");
// remove the surrounding white-space
field = field.Trim();
// remove all white space before/after the description
value = value.Trim();
yield return new Tuple<string, string>(field, value);
}
}
}
}
Here's a quick console project that will use the class to output your format to the console the way you want.
using System;
using System.IO;
namespace TestConsoleProject
{
class Program
{
static void Main(string[] args)
{
var lines = File.ReadLines(args[0]);
var reader = new WeirdLineFormatReader();
var tuples = reader.ReadLines(lines);
foreach (var tuple in tuples)
Console.WriteLine("{0} - {1}", tuple.Item1, tuple.Item2);
Console.ReadKey();
}
}
}
Just for the fun of it and also because I suspect you are only showing us a couple of the lines in a much larger text file; here's a format for unit testing when you find that you need to add more code to the ReadLines(string[]) method later.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
using TestConsoleProject;
namespace UnitTestProject
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestFormatter_WithoutBrackets()
{
// Arrange
var reader = new WeirdLineFormatReader();
string[] lines = {
"field20D.name = Reference"
};
// Act
var tuples = reader.ReadLines(lines).ToList();
// Assert
Assert.AreEqual(tuples[0].Item1, "20D", "Field 20D did not format correctly, Actual:" + tuples[0].Item1);
Assert.AreEqual(tuples[0].Item2, "Reference", "Field 20D's description did not format correctly, Actual:" + tuples[0].Item2);
}
[TestMethod]
public void TestFormatter_WithBrackets()
{
// Arrange
var reader = new WeirdLineFormatReader();
string[] lines = {
"field20[103].name = Sender's Reference"
};
// Act
var tuples = reader.ReadLines(lines).ToList();
// Assert
Assert.AreEqual(tuples[0].Item1, "20[103]", "Field 20[103] did not format correctly, Actual:" + tuples[0].Item1);
Assert.AreEqual(tuples[0].Item2, "Sender's Reference", "Field 20[103]'s description did not format correctly, Actual:" + tuples[0].Item2);
}
}
}
Using this unit test project you can quickly write new tests for edge cases that you discover. After you modify the ReadLines() method, you can re-run all the unit tests to see if you broke any of the older tests.
Pseudo:
create a dictionary of key value pairs
split on carriage return
split on equals sign (can there be an equals sign in the value?)
regex the first half to get everything between 'field' and '.name', put that in the key
put the split from after the equals sign in the value
now you can reference your dictionary by key:
entry = myDictionary["20D"];
return $"{entry.Key} - {entry.value}";
I am currently working on a project that involves taking a text file with information in it and storing the values into an array for use in determining if a certain book should be "split" based on its ID.
I have declared a string array in the class that is executing the method for this task, and assigning the values from the text file using a StreamReader.
Here is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Odbc;
using System.Data.OleDb;
using System.IO;
namespace ElectionsPollBooks
{
class dbElections
{
//arrays, ints, for pollbook splits
string[] as_splitNumbers;
int i_splitCount;
public void Process()
{
//opens conenction
OpenConn();
//Gets the precinct info for later parsing
GetDistrictInfo();
//populate splits array
PopulateSplits();
//the hard work
SeperateDataSet();
CloseConn();
}
//...other methods in here, not related
private void PopulateSplits()
{
//sets the count
i_splitCount = 0;
//reads the split file
StreamReader sr_splits = new StreamReader(#"a\file\path\here\.txt");
//begin populating the array
while (sr_splits.ReadLine() != null)
{
//split ID
as_splitNumbers[i_splitCount] = sr_splits.ReadLine();
i_splitCount = i_splitCount + 1;
}
sr_splits.Close();
sr_splits.Dispose();
}
}
}
Visual Studio is telling me at this line:
string[] as_splitNumbers;
That:
"as_splitNumbers is never assigned to and will always return a null value."
When I also run the program, it throws a NullReferenceException during the while loop.
My question is then, what am I doing wrong when it comes to assigning the StreamReader values to the as_splitNumbers array? What am I missing in my logic?
Thank you.
You're not initializing your array with a size.
What you could do if you don't know the size is use List<int>.
Change
string[] as_splitNumbers
to
List<string> as_SplitNumbers = new List<string>();
and your method to:
private void PopulateSplits()
{
//sets the count
i_splitCount = 0;
//reads the split file
using(StreamReader sr_splits = new StreamReader(#"a\file\path\here\.txt"))
{
//begin populating the array
while (sr_splits.ReadLine() != null)
{
//split ID
string split = sr_splits.ReadLine();
as_splitNumbers.Add(split);
i_splitCount = i_splitCount + 1;
}
}
}
If what you're sending it to (SeperateDataSet();?) requires an array, you can cast it by using _asSplitNumbers.ToArray() later on. List<T> just allows you to add without knowing the size.
Try to use a List (System.Enumerable).
Because you donn't know the size of the array before reading.
At the declaration of the variable it will means:
List<string> as_splitNumbers = new List<string>();
in the loop you can simply write
as_splitNumbers.Add(sr_splits.ReadLine())
and it will work!
Your as_splitNumbers array is never allocated. You need to initialize the array with a size first.
string[] as_splitNumbers = new string[SIZE];
However, it seems you should just use a List in your case.
List<string> as_splitNumbers = new List<string>();
Then
//split ID
as_splitNumbers.Add(sr_splits.ReadLine());
So I am trying to sort a file out in a descending order.
The text file looks something like this:
%[TIMESTAMP=1441737006376][EVENT=agentStateEvent][queue=79651][agentID=61871][extension=22801][state=2][reason=0]%
%[TIMESTAMP=1441737006102][EVENT=agentStateEvent][queue=79654][agentID=62278][extension=22828][state=2][reason=0]%
%[TIMESTAMP=1441737006105][EVENT=CallControlTerminalConnectionTalking][callID=2619][ucid=10000026191441907765][deviceType=1][deviceName=21775][Queue=][Trunk=384:82][TrunkType=1][TrunkState=1][Cause=100][CalledDeviceID=07956679058][CallingDeviceID=21775][extension=21775]%
and basically I want the end result to only output unique values of the timestamp. I have used substring to get rid of the excess text, and it outputs fine as shown below:
[TIMESTAMP=1441737006376]
[TIMESTAMP=1441737006102]
[TIMESTAMP=1441737006105]
however i want it to order in the following order (basically numeric descending to ascending):
[TIMESTAMP=1441737006102]
[TIMESTAMP=1441737006105]
[TIMESTAMP=1441737006376]
I have tried the .sort and .orderBy but not having any joy. I wouldve using this prior to doing any substring formatting wouldve sufficed but clearly not.
Code is as follows:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FedSorter
{
class Program
{
static void Main(string[] args)
{
int counter = 0;
string line;
string readIn = "C:\\Users\\xxx\\Desktop\\Files\\ex1.txt";
System.IO.TextWriter writeOut = new StreamWriter("C:\\Users\\xxx\\Desktop\\Files\\ex1_new.txt");
List<String> list = new List<String>();
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader(readIn);
string contents = "";
string checkValues = "";
while ((line = file.ReadLine()) != null)
{
string text = line;
text = text.Substring(1, 25);
if (!checkValues.Contains(text))
{
list.Add(text);
Console.WriteLine(text);
writeOut.WriteLine(text);
counter++;
}
contents = text;
checkValues += contents + ",";
}
list = list.OrderBy(x => x).ToList();
writeOut.Close();
file.Close();
orderingFile();
}
public static void orderingFile()
{
string line = "";
string readIn = "C:\\Users\\xxx\\Desktop\\Files\\ex1_new.txt";
System.IO.TextWriter writeOut = new StreamWriter("C:\\Users\\xxx\\Desktop\\Files\\ex1_new2.txt");
List<String> ordering = new List<String>();
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader(readIn);
while ((line = file.ReadLine()) != null)
{
ordering.OrderBy(x => x).ToList();
ordering.Add(line);
writeOut.WriteLine(line);
}
writeOut.Close();
file.Close();
}
}
}
You are creating a new list and you need to assign it to the variable
list = list.OrderBy(x => x).ToList();
However it doesn't look like you even use list after you create and sort it. Additionally you have the same issue in the orderingFile method with
ordering.OrderBy(x => x).ToList();
However instead of sorting and creating a new list on each line it would be better to use a SortedList<TKey, TValue> that will keep the contents sorted as you add to it.
But again you are not actually using the ordering list after you finish adding to it in the foreach. If you are looking to read the values in a file, sort them and then output them to another file, then you need to do it in that order.
Aside from #juharr's correct answer, you would do well to take advantage of LINQ to simplify your code greatly.
string readIn = "C:\\Users\\xxx\\Desktop\\Files\\ex1.txt";
var timestamps = File.ReadAllLines(readIn)
.Select(l => l.Substring(1, 25))
.Distinct()
.OrderBy(t => t)
.ToArray();
To write out the values, you can either use a foreach on timestamps and write out each line to your TextWriter, or you can use the File class again:
string readOut = "C:\\Users\\xxx\\Desktop\\Files\\ex1_new.txt";
File.WriteAllLines(readOut, timestamps);
//notice I've changed it to ToArray in the first part instead of ToList.