how to loop , read and write the folders and subfolders files - c#

I am having a problem writing the files in folders and subfolders .
For Example:- test is the main folder
1) C:\test\
and i want to read and write the subfolder files
2)C:\test\12-05-2011\12-05-2011.txt
3)C:\test\13-05-2011\13-05-2011.txt
4)C:\test\14-05-2011\14-05-2011.txt
My code is:
private void button1_Click(object sender, EventArgs e)
{
const string Path1 = #"C:\test";
DoOnSubfolders(Path1);
try
{
StreamReader reader1 = File.OpenText(Path1);
string str = reader1.ReadToEnd();
reader1.Close();
reader1.Dispose();
File.Delete(Path1);
string[] Strarray = str.Split(new char[] { Strings.ChrW(10) });
int abc = Strarray.Length - 2;
int xyz = 0;
while (xyz <= abc)
}
I am getting an error. The error is
Access to the path 'C:\test' is denied.
Can anyone say me what i need to change in this code?

At first you could flatten your recursive calls by calling DirectoryInfo.GetFiles(string, SearchOption) and setting the SearchOption to AllDirectories.
What's also a common mistake (but not clear from your question) is that a directory needs to be created, before you can create a file. Simply call Directory.CreateDirectory(). And put in the complete path (without filename) into it. It will automatically do nothing if the directory already exists and is also able to create the whole needed structure. So no checks or recursive calls are needed (maybe a try-catch if you don't have write access).
Update
So here is an example that reads in a file, does some conversion on each line and writes the result into a new file. If this works properly the original file will be replaced by the converted one.
private static void ConvertFiles(string pathToSearchRecursive, string searchPattern)
{
var dir = new DirectoryInfo(pathToSearchRecursive);
if (!dir.Exists)
{
throw new ArgumentException("Directory doesn't exists: " + dir.ToString());
}
if (String.IsNullOrEmpty(searchPattern))
{
throw new ArgumentNullException("searchPattern");
}
foreach (var file in dir.GetFiles(searchPattern, SearchOption.AllDirectories))
{
var tempFile = Path.GetTempFileName();
// Use the using statement to make sure file is closed at the end or on error.
using (var reader = file.OpenText())
using (var writer = new StreamWriter(tempFile))
{
string line;
while (null != (line = reader.ReadLine()))
{
var split = line.Split((char)10);
foreach (var item in split)
{
writer.WriteLine(item);
}
}
}
// Replace the original file be the converted one (if needed)
////File.Copy(tempFile, file.FullName, true);
}
}
In your case you could call this function
ConvertFiles(#"D:\test", "*.*")

To recursively walk the sub-folders, you need a recursive function ie. One that calls itself. here is an example that should be enough for you to work with:
static void Main(string[] args)
{
const string path = #"C:\temp\";
DoOnSubfolders(path);
}
private static void DoOnSubfolders(string rootPath)
{
DirectoryInfo d = new DirectoryInfo(rootPath);
FileInfo[] fis = d.GetFiles();
foreach (var fi in fis)
{
string str = File.ReadAllText(fi.FullName);
//do your stuff
}
DirectoryInfo[] ds = d.GetDirectories();
foreach (var info in ds)
{
DoOnSubfolders(info.FullName);
}
}

You need use class Directory info and FileInfo.
DirectoryInfo d = new DirectoryInfo("c:\\test");
FileInfo [] fis = d.GetFiles();
DirectoryInfo [] ds = d.GetDirectories();

Here's a quick one liner to write the contents of all text files in a given directory (and all subdirectories) to the console:
Directory.GetFiles(myDirectory,"*.txt*",SearchOption.AllDirectories)
.ToList()
.ForEach(a => Console.WriteLine(File.ReadAllText(a)));

This code:
const string Path1 = #"C:\test";
StreamReader reader1 = File.OpenText(Path1);
Says open "c:\test" as a text file... The error you're getting is:
Access to the path 'C:\test' is denied
You're getting the error because as you stated above, 'c:\test' is a folder. You can't open folders like they are text files, hence the error...
A basic (full depth search) for files with a .txt extension looks like this:
static void Main(string[] args) {
ProcessDir(#"c:\test");
}
static void ProcessDir(string currentPath) {
foreach (var file in Directory.GetFiles(currentPath, "*.txt")) {
// Process each file (replace this with your code / function call /
// change signature to allow a delegate to be passed in... etc
// StreamReader reader1 = File.OpenText(file); // etc
Console.WriteLine("File: {0}", file);
}
// recurse (may not be necessary), call each subfolder to see
// if there's more hiding below
foreach (var subFolder in Directory.GetDirectories(currentPath)) {
ProcessDir(subFolder);
}
}

Have a look at http://support.microsoft.com/kb/303974 for a start. The secret is Directory.GetDirectories in System.IO.

You have to configure (NTFS) security on the c:\Test folder.
Normally you would have the application run under non-admininstrator account so the account that is running the program should have access.
If you are running on Vista or Windows 7 with UAC, you might be an administrator but you will not be using the administrative (elevated) permissions by default.
EDIT
Look at these lines:
const string Path1 = #"C:\test";
DoOnSubfolders(Path1);
try
{
StreamReader reader1 = File.OpenText(Path1);
That last line is trying to read the FOLDER 'c:\test' as if it was a text file.
You can't do that. What are you trying to accomplish there?

Related

C# not reading files properly when using .Path class

I'm trying to read a folder and do a look at the file names. Using this code:
try
{
var folderPath = #"C:\Users\Gamer\source\repos\carValLocal\carValLocal\files\";
foreach (string file in Directory.EnumerateFiles(Path.GetFileName(folderPath)))
{
var ha = file;
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.ReadLine();
}
Unfortunately, I'm getting the following error:
The path is not of a legal form
My original filepath:
var folderPath = #"C:\Users\Gamer\source\repos\carValLocal\carValLocal\files\";
To find the bad chars I wrote this bit of code:
string illegal = #"C:\Users\Gamer\source\repos\carValLocal\carValLocal\files\";
string invalid = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
foreach (char c in invalid)
{
illegal = illegal.Replace(c.ToString(), "");
}
which came back with:
"CUsersGamersourcereposcarValLocalcarValLocalfiles"
Which clearly isn't a file name.
If I don't use the Path class, it still finds files. How can I make this work because everything I've tried (like removing illegal chars) just doesn't work.
Well, for given folder path
var folderPath = #"C:\Users\Gamer\source\repos\carValLocal\carValLocal\files\";
The existing call
Path.GetFileName(folderPath);
returns empty string: "" since
C:\Users\Gamer\source\repos\carValLocal\carValLocal\files\
\ /|
--------------------- directory ------------------------ file
if you want to look for files in C:\Users\Gamer\source\repos\carValLocal\carValLocal\files you can
use Path.GetDirectoryName:
foreach (string file in Directory.EnumerateFiles(Path.GetDirectoryName(folderPath)))
{
...
}
If you want some kind of path manipulation, try DirectoryInfo, e.g. let's have a look for files in
C:\Users\Gamer\source\repos\carValLocal\carValLocal
Code:
var folderPath = #"C:\Users\Gamer\source\repos\carValLocal\carValLocal\files\";
DirectoryInfo di = new DirectoryInfo(folderPath);
foreach (string file in Directory.EnumerateFiles(di.Parent.FullName)) {
...
}

How to crop string from multiple txt files?

I have thousands of .log files and I need to find some string in all of the files.
I will explain with example: on all of .log files I have string calles "AAA" and after that string I have anumber that can be diffrenet from one log file to other log file. I know how to search the AAA string. what I dont knew is how to crop only the string number that is after the AAA string.
update:
the .log file containes a lot of lines.
on the .log file I have only 1 line that contains the string "A12A".
after that line I have anumber (for examle: 5465).
what I need is to extract the number after the A12A.
note: there is a spacing between the A12A to the 5465 string number.
example:
.log file : "assddsf dfdfsd dfd A12A 5465 dffdsfsdf dfdf dfdf "
what I need to extract: 5465.
what I have so far is:
// Modify this path as necessary.
string startFolder = #"c:\program files\Microsoft Visual Studio 9.0\";
// Take a snapshot of the file system.
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(startFolder);
// This method assumes that the application has discovery permissions
// for all folders under the specified path.
IEnumerable<System.IO.FileInfo> fileList = dir.GetFiles("*.*", System.IO.SearchOption.AllDirectories);
string searchTerm = #"Visual Studio";
// Search the contents of each file.
// A regular expression created with the RegEx class
// could be used instead of the Contains method.
// queryMatchingFiles is an IEnumerable<string>.
var queryMatchingFiles =
from file in fileList
where file.Extension == ".htm"
let fileText = GetFileText(file.FullName)
where fileText.Contains(searchTerm)
select file.FullName;
// Execute the query.
Console.WriteLine("The term \"{0}\" was found in:", searchTerm);
foreach (string filename in queryMatchingFiles)
{
Console.WriteLine(filename);
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
// Read the contents of the file.
static string GetFileText(string name)
{
string fileContents = String.Empty;
// If the file has been deleted since we took
// the snapshot, ignore it and return the empty string.
if (System.IO.File.Exists(name))
{
fileContents = System.IO.File.ReadAllText(name);
}
return fileContents;
}
I would recommend the following code for doing the search itself:
private static readonly string _SearchPattern = "A12A";
private static readonly Regex _NumberExtractor = new Regex(#"\d+");
private static IEnumerable<Tuple<String, int>> FindMatches()
{
var startFolder = #"D:\";
var filePattern = #"*.htm";
var matchingFiles = Directory.EnumerateFiles(startFolder, filePattern, SearchOption.AllDirectories);
foreach (var file in matchingFiles)
{
// What encoding do your files use?
var lines = File.ReadLines(file, Encoding.UTF8);
foreach (var line in lines)
{
int number;
if (TryGetNumber(line, out number))
{
yield return Tuple.Create(file, number);
// Stop searching that file and continue with the next one.
break;
}
}
}
}
private static bool TryGetNumber(string line, out int number)
{
number = 0;
// Should casing be ignored??
var index = line.IndexOf(_SearchPattern, StringComparison.InvariantCultureIgnoreCase);
if (index >= 0)
{
var numberRaw = line.Substring(index + _SearchPattern.Length);
var match = _NumberExtractor.Match(numberRaw);
return Int32.TryParse(match.Value, out number);
}
return false;
}
The reasons are that when doing I/O operations, the drive itself is normally the bottleneck. So it doesn't make sense to do anything in parallel or to read a lot of data from the file into memory without using it.
By using the Directory.EnumerateFiles method the drive will be searched lazily and you can start examining the first file, right after it was found. The same holds true for the File.ReadLines method. It lazily iterates through the file while you are searching for your pattern.
Through this approach you should get a maximum speed (depending on your hard-drive performance) cause it makes the minimum needed I/O calls needed to get the files and content to your code.

Reading contents from several files and writing to one file

In my application there is a situation like this.Before creating a file, my application search for files in a directory under a particular filename. If any file/files found, then it should read each files contents and write these contents(of each file) to a new file. I have googled many and tried some like this:
string temp_file_format = "ScriptLog_" + DateTime.Now.ToString("dd_MM_yyyy_HH");
string[] files = Directory.GetFiles(path,temp_file_format);
foreach (FileAccess finfo in files)
{
string text = File.ReadAllText(finfo);
}
and
System.IO.DirectoryInfo dir = new DirectoryInfo(path);
System.IO.FileInfo[] files = dir.GetFiles(temp_file_format);
foreach (FileInfo finfo in files)
{
finfo.OpenRead();
}
But all these failed..Can anyone show me an alternative for this?
Is there anything wrong in my temp_file_format string?
It will be nice if I could prepend these contents to the new file. Else also, no worries..
any help would be really appreciated..
This is a compete working implementation that does all of that
without reading everything in memory at one time (which doesn't work for large files)
without keeping any files open for more than the required time
using System.IO;
using System.Linq;
public static class Program {
public static void Main()
{
var all = Directory.GetFiles("/tmp", "*.cpp")
.SelectMany(File.ReadAllLines);
using (var w = new StreamWriter("/tmp/output.txt"))
foreach(var line in all)
w.WriteLine(line);
}
}
I tested it on mono 2.10, and it should work on any .NET 4.0+ (for File.ReadAllLines which is a lazy linewise enumerable)
Here's a short snippet that reads all the files and out puts them to the path outputPath
var lines = from file in Directory.GetFiles(path,temp_file_format)
from line in File.ReadAllLines(file)
select line;
File.WriteAllLines(outputPath, content);
The problem you are having with your code is not really related to reading files but simply trying to use an object as a type it's not. Directory.GetFiles returns an array of string and File.ReadXXX and File.OpenRead expects the path as a string. So you simply need to pass each of the strings returned as the path argument to the appropriate method. The above is one such example. Hope it helps both solve your problem and explain the actually issue with your code
try this:
foreach (FileInfo finfo in files)
{
try
{
using (StreamReader sr = new StreamReader("finfo "))
{
String line = sr.ReadToEnd();
Console.WriteLine(line);
}
}
catch (Exception e)
{
Console.WriteLine("The file could not be read:");
Console.WriteLine(e.Message);
}
}
using (var output = File.Create(outputPath))
{
foreach (var file in Directory.GetFiles(InputPath,temp_file_format))
{
using (var input = File.OpenRead(file))
{
input.CopyTo(output);
}
}
}

Read text file from C# Resources

I need to read a file from my resources and add it to a list.
my code:
private void Form1_Load(object sender, EventArgs e)
{
using (StreamReader r = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("myProg.myText.txt")))
{
//The Only Options Here Are BaseStream & CurrentEncoding
}
}
Ive searched for this and only have gotten answers like "Assembly.GetExecutingAssembly...." but my program doesnt have the option of Assembly.?
Try something like this :
string resource_data = Properties.Resources.test;
List<string> words = resource_data.Split(new[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries).ToList();
Where
You need to include using System.Reflection; in your header in order to get access to Assembly. This is only for when you mark a file as "Embedded Resource" in VS.
var filename = "MyFile.txt"
System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("YourNameSpace." + filename));
As long as you include 'using System.Reflection;' you can access Assembly like this:
Assembly.GetExecutingAssembly().GetManifestResourceStream("YourNamespace." + filename);
Or if you don't need to vary filename just use:
Assembly.GetExecutingAssembly().GetManifestResourceStream("YourNamespace.MyFile.txt");
The full code should look like this:
using(var reader = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("myProg.m‌​yText.txt"))
{
string line;
while ((line = reader.ReadLine()) != null)
{
// Do some stuff here with your textfile
}
}
Just to follow on this, AppDeveloper solution is the way to go.
string resource_data = Properties.Resources.test;
string [] words = resource_data.Split(new[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries);
foreach(string lines in words){
.....
}
[TestCategory("THISISATEST")]
public void TestResourcesReacheability()
{
byte[] x = NAMESPACE.Properties.Resources.ExcelTestFile;
string fileTempLocation = Path.GetTempPath() + "temp.xls";
System.IO.File.WriteAllBytes(fileTempLocation, x);
File.Copy(fileTempLocation, "D:\\new.xls");
}
You get the resouce file as a byte array, so you can use the WriteAllBytes to create a new file. If you don't know where can you write the file (cause of permissions and access) you can use the Path.GetTempPath() to use the PC temporary folder to write the new file and then you can copy or work from there.

C# - Search for Matching FileNames in a Directory using SearchOption

Background: I'm developing a WinForms application using C# with an OpenFileDialog & FileBrowserDialog that will 1) search for a specific string in the filenames of a specified source directory 2) copy files to consolidated directory 3) convert multiple files from excel to csv files, and then 3) convert all the generated csv files into 1 big csv file using a command line executable
Example: MSDN provides a code example that lists all of the directories and files that begin with the letter "c" in "c:\". at http://msdn.microsoft.com/en-us/library/ms143448.aspx so I based my code on that...
Problem: The code doesn't copy any files to the consolidated folder so I'm pretty sure the search doesn't work.
What should I change on here? It doesn't work :
string files = "*.xlsx";
void DirSearch(string sDir)
{
try
{
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d, files))
{
// Is this the file we are looking for?
// check excel files for corp name in the filename.
if (f.Contains(m_sc.get_Corp()))
{
// check if thread is cancelled
if (m_EventStop.WaitOne(0, true))
{
// clean-up operations may be placed here
// ...
// inform main thread that this thread stopped
m_EventStopped.Set();
return;
}
else
{
string path = sDir;
string searchPattern = m_sc.get_Corp();
// A file has been found in this directory
DirectoryInfo di = new DirectoryInfo(path);
DirectoryInfo[] directories = di.GetDirectories(searchPattern, SearchOption.TopDirectoryOnly);
foreach (FileInfo file in files)
{
try
{
// Copy each selected xlsx files into the specified TargetFolder
System.IO.File.Copy(FileName, consolidatedFolder + #"\" + System.IO.Path.GetFileName(FileName));
Log("File" + FileName + " has been copied to " + consolidatedFolder + #"\" + System.IO.Path.GetFileName(sourceFileOpenFileDialog.FileName));
// Convert each selected XLSX File to CSV Using the command prompt code...
}
}
}
}
The code you've posted does two separate search loops:
first:
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d, files))
{
// Is this the file we are looking for?
// check excel files for corp name in the filename.
if (f.Contains(m_sc.get_Corp()))
{
then within that it also does:
string path = sDir;
string searchPattern = m_sc.get_Corp();
// A file has been found in this directory
DirectoryInfo di = new DirectoryInfo(path);
DirectoryInfo[] directories = di.GetDirectories(searchPattern, SearchOption.TopDirectoryOnly);
foreach (FileInfo file in files)
{
In the first one you are looking for files matching m_sc.get_Corp();, in the second one you are lookinf for directories...
In fact... your code (pseudo-code?) makes no sense...
Try:
taking your time
tidying up the code yourself
if you rewrite it slowly and break this into smaller chunks, you might spot what you are doing wrong.
Try cleaning up a bit, below is some code that will put you on the path, I've excluded the CSV conversion and the merge, hopefully you will get the idea.
private void YourFileRoutine(string sourceDirectoryPath, string consolidatedDirectoryPath)
{
var excelFiles = new DirectoryInfo(sourceDirectoryPath).GetFiles().Where(x => x.Extension == ".xlsx");
//Copy all Excel Files to consolidated Directory
foreach (var excelFile in excelFiles)
{
FileInfo copiedFile = excelFile.CopyTo(String.Concat(consolidatedDirectoryPath, excelFile.Name)); // Make sure consolidatedDirectoryPath as a "\" maybe use Path.Combine()?
// ConvertToCSV( Do your CSV conversion here, the Path will be = Path.GetFullPath(copiedFile);
}
// Merge CSV's
var csvFiles = new DirectoryInfo(consolidatedDirectoryPath).GetFiles().Where(x => x.Extension == ".csv");
// SomeMergeMethod that iterates through this FileInfo collection?
}

Categories

Resources