I am trying to read a list in text file and move the files source to target directory. But as I am trying to read this file using for statement it's giving me following error :
foreach statement cannot operate on variables of type
System.IO.StreamReader because System.IO.StreamReader does not
contain a public definition for GetEnumerator
Not sure if this is issue with file creation or some alternate approach is needed here to read and then move files.
Please advise.
Here's the code:
static void Main(string[] args)
{
create_source_fileList();
string source_dir = System.Configuration.ConfigurationSettings.AppSettings["SourceDir"];
string target_dir = System.Configuration.ConfigurationSettings.AppSettings["TargetDir"];
string dpath = target_dir + "Diff" + ".txt";
TextWriter df = new StreamWriter(dpath);
DirectoryInfo sourceinfo = new DirectoryInfo(source_dir);
DirectoryInfo targetinfo = new DirectoryInfo(target_dir);
string[] source_f_list = File.ReadAllLines(target_dir + "Source_File_List.txt");
string[] target_f_list = File.ReadAllLines(target_dir + "Target_File_List.txt");
IEnumerable<String> file_list_diff = source_f_list.Except(target_f_list);
string diff_list = string.Join(Environment.NewLine, file_list_diff);
df.WriteLine(string.Join(Environment.NewLine, file_list_diff));
df.Close();
System.IO.StreamReader file_read = new System.IO.StreamReader(target_dir + "\\Diff.txt");
if (!Directory.Exists(targetinfo.FullName))
{
Directory.CreateDirectory(targetinfo.FullName);
}
/*foreach (FileInfo fi in sourceinfo.GetFiles())
{
fi.CopyTo(Path.Combine(targetinfo.ToString(), fi.Name), true);
}*/
foreach (string file in file_read) // Error With For Loop
{
}
create_target_fileList();
}
Yes, you can't use foreach directly with StreamReader. It doesn't have the required members for foreach to work.
Options:
Use File.ReadLines instead:
string path = Path.Combine(targetDir, "Diff.txt");
foreach (string file in File.ReadLines(path))
{
// ...
}
Repeatedly call ReadLine on your StreamReader, which should be in a using statement and is simply obtained using File.OpenText:
string path = Path.Combine(targetDir, "Diff.txt");
using (TextReader reader = File.OpenText(path))
{
string file;
while ((file = reader.ReadLine()) != null)
{
// ...
}
}
Note that I've made the variable names a bit cleaner too - idiomatic variable names in C# are things like sourceFileList rather than source_f_list.
Additionally, I'd encourage you to use File.WriteAllText earlier on, rather than the way you're using df (without a using statement, and opening it much earlier than you need to).
Related
I am making an app in C# where I am searching if the file exists in the text file or not. If it does not exist then, it would add it in the text file and then append it in a List. But, for some reason the list only takes one file and ends at that point. So, can someone help me with what is the problem in this foreach loop?
static void CheckNewFile()
{
string path_f = #"File_Address_where_Text_file_exists";
var new_file = new List<string>();
if (!File.Exists(path_f)) # Checking if the text file exists or not and then creating it
{
var myFile = File.Create(path_f);
myFile.Close();
}
DirectoryInfo hdDirectoryInWhichToSearch = new DirectoryInfo(#"File_Address_in_which_Files_need_to_be_searched");
FileInfo[] filesInDir = hdDirectoryInWhichToSearch.GetFiles("AC" + "*" + "*.*" + "AC"); # Format of the file to be searched
foreach (FileInfo foundFile in filesInDir) # foreach for the files in the directory
{
string fullName = foundFile.FullName;
int flag = 0;
var lines = File.ReadLines(path_f);
foreach (var line in lines) # Reading line by line and checking if the file exists in the text file before
{
if (String.Equals(line, fullName))
{
flag += 1;
break;
}
}
if (flag < 1)
{
if (new FileInfo(path_f).Length == 0) # File Address is appended in the File
{
//TextWriter tw = new StreamWriter(path_f);
//tw.WriteLine(fullName);
//tw.Close();
}
else
{
//using (var tw = new StreamWriter(path_f, true))
//{
// tw.WriteLine(fullName);
//}
}
new_file.Add(fullName.ToString()); # Adding File Address to the list
flag = 0;
break;
}
}
}
Remove the last break. It is causing the program flow to leave the enclosing foreach loop with the file names.
As the other poster mentioned, you're breaking out of your loop early in the if block.
However, there isn't really a need for the flag (or loop or if block) at all. Your method could be simplified greatly by using a little System.Linq and just using Directory to find the new files by comparing their paths to the contents of the input file.
For example:
static List<string> CheckForNewFiles(string filePath, string searchDir,
string searchPattern)
{
// Create file if it doesn't exist
if (!File.Exists(filePath)) using (File.Create(filePath)) ;
// Get list of files that match search pattern which aren't contained in our file
var newFiles = Directory
.GetFiles(searchDir, searchPattern)
.Where(match => !File.ReadLines(filePath).Contains(match))
.ToList();
// Add the new file paths to our file
File.AppendAllLines(filePath, newFiles);
// Return the list of new files (?)
return newFiles;
}
In use it migth look something like:
public static void Main()
{
Console.WriteLine("Checking for new files...");
var newFiles = CheckForNewFiles(#"c:\temp\paths.txt", #"c:\temp\temp", "*.png");
Console.WriteLine($"{newFiles.Count} files found since last search.");
if (newFiles.Any())
{
Console.WriteLine(" -> " + string.Join(Environment.NewLine + " -> ", newFiles));
}
Console.ReadLine();
}
How can I read line by line for a list of files?
I have a directory with a number of files, I need to save all the files in a list and process them one by one, line by line.
So far I have done the following :
//fetching all files from directory
DirectoryInfo d = new DirectoryInfo("path");
Dictionary<int, FileInfo> DatFiles = new Dictionary<int, FileInfo>();
int filecounter = 1;
foreach (var dat in d.EnumerateFiles())
{
DatFiles.Add(filecounter, dat);
filecounter++;
}
Console.WriteLine(filecounter);
foreach (var fileName in DatFiles)
{
foreach (var line in File.ReadLines(fileName.Value.OpenText().ToString()))
{
//run some methods
}
}
When executing, I'm getting an exception, file not found. Even though the list is full of file names.
EnumerateFiles() returns a list of FileInfo objects, and File.ReadLines() takes a string path argument; you probably want to use File.ReadLines(fileName.Value.FullName) in your foreach as that gives the path to the actual file; OpenText() returns a StreamReader object.
This smaller code should do the task
var files = Directory.GetFiles("path");
foreach(var f in files)
{
using(StreamReader reader = new StreamReader(f))
{
var lines = reader.ReadToEnd().Split(new string[]{Environment.NewLine});
// Do here
}
}
When all else fails refer to the documentation
// Open the stream and read it back.
using (StreamReader sr = fi.OpenText())
{
string s = "";
while ((s = sr.ReadLine()) != null)
{
Console.WriteLine(s);
}
}
I am trying to load all my "error log files" into one (hopefully not gigantic) string, and then assign that string to a Multiline textBox:
private void PopulateTextBox()
{
const string errLogDir = "\\ErrorLog";
Directory.CreateDirectory(errLogDir);
StringBuilder sb = new StringBuilder();
DirectoryInfo di = new DirectoryInfo(errLogDir);
FileInfo[] files = di.GetFiles("*.txt");
foreach (FileInfo fi in files)
{
sb.AppendLine(String.Format("*** {0} ***", fi.FullName));
using (StreamReader sr = new StreamReader(fi.FullName))
{
String line;
while ((line = sr.ReadLine()) != null)
{
sb.AppendLine(line);
}
}
sb.AppendLine(String.Empty);
}
string errLogContents = sb.ToString();
MessageBox.Show(String.Format("errLogContents is {0}", errLogContents));
textBoxErrLogsContents.Text = sb.ToString();
}
There is one file (named "ExceptionLog_2.11.2009.txt"), with some text data, in the \ErrorLog directory directly below the .exe directory (files are created programatically when exceptions occur).
So why am I seeing an empty string in the MessageBox.Show() and nothing is in textBoxErrLogsContents?
UPDATE
Virtually the same code works in a VS 2013 "Sandbox" app, with just a different directory name, file type, and textBox name:
const string errLogDir = #"C:\MiscInWindows7";
Directory.CreateDirectory(errLogDir);
StringBuilder sb = new StringBuilder();
DirectoryInfo di = new DirectoryInfo(errLogDir);
FileInfo[] files = di.GetFiles("*.xml");
foreach (FileInfo fi in files)
{
sb.AppendLine(String.Format("*** {0} ***", fi.FullName));
using (StreamReader sr = new StreamReader(fi.FullName))
{
String line;
while ((line = sr.ReadLine()) != null)
{
sb.AppendLine(line);
}
}
sb.AppendLine(String.Empty);
}
string errLogContents = sb.ToString();
MessageBox.Show(String.Format("errLogContents is {0}", errLogContents));
textBox7.Text = sb.ToString();
UPDATE 2
ctacke whammed the spike on the noggin re: my not providing the full path. This works:
private void PopulateTextBox()
{
String logDirPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
String fullPath = logDirPath + "\\ErrorLog";
StringBuilder sb = new StringBuilder();
DirectoryInfo di;
if (!Directory.Exists(fullPath))
{
di = Directory.CreateDirectory(fullPath);
}
else
{
di = new DirectoryInfo(fullPath);
}
FileInfo[] files = di.GetFiles("*.err");
foreach (FileInfo fi in files)
{
sb.AppendLine(String.Format("*** {0} ***", fi.FullName));
using (StreamReader sr = new StreamReader(fi.FullName))
{
String line;
while ((line = sr.ReadLine()) != null)
{
sb.AppendLine(line);
}
}
sb.AppendLine(String.Empty);
}
textBoxErrLogsContents.Text = sb.ToString();
}
This doesn't make any sense:
const string errLogDir = "\\ErrorLog";
Directory.CreateDirectory(errLogDir);
StringBuilder sb = new StringBuilder();
DirectoryInfo di = new DirectoryInfo(errLogDir);
FileInfo[] files = di.GetFiles("*.txt");
So you're creating a new directory, and then trying to read files from it. In this case, you're creating the directory at the root (i.e. "C:\ErrorLog", if the drive of the current working directory is C:).
If the directory you asked to create already exists, CreateDirectory just returns the DirectoryInfo object. But if you create a new directory and then try to get files from it, it's pretty likely that there will be no files at all because you just created an empty directory.
It's likely that you wanted that to be
const string errorLogDir = "ErrorLog";
That will cause the directory to be created as a subdirectory of the current working directory.
By the way, there's no readon to have:
Directory.CreateDirectory(errLogDir);
DirectoryInfo di = new DirectoryInfo(errLogDir);
CreateDirectory returns a DirectoryInfo object. So you can write:
DirectoryInfo di = new DirectoryInfo(errLogDir);
Now, it's quite possible that the EXE directory is not the same as the current working directory. If you want to get the information from the EXE's subdirectory, then you have to explicitly say so:
string fullName = Assembly.GetEntryAssembly().Location;
string exeDirectory = Path.GetDirectoryName(fullName);
string fullErrLogDir = Path.Combine(exeDirectory, errLogDir);
DirectoryInfo di = Directory.CreateDirectory(fullErrLogDir);
Finally, you can replace all of this code:
using (StreamReader sr = new StreamReader(fi.FullName))
{
String line;
while ((line = sr.ReadLine()) != null)
{
sb.AppendLine(line);
}
}
With a single line:
sb.AppendLine(File.ReadAllText(fi.FullName));
First, calling CreateDirectory in all cases is a bad idea. It's confusing. Instead, check to see if the directory exists, and if it doesn't then create it and exit the function (because if you created it, you know there's no data). This would have found your error much faster and also prevented #Jim Mischel's (and everyone else's) confusion.
The problem with your code is actually rooted in one of your comments. You say the file, as seen from your PC with WMDC, is at Computer\WindowsCE\Program Files\HHS\ErrorLog. On the device itself that equates to \Program Files\HHS\ErrorLog not just \ErrorLog. Remember, there are no relative paths on Windows CE devices.
I am trying to create new files with the names created by data from lines in several files.
I want to read all lines of just the .txt files in a folder and then create files from that list.
The files are have various amounts of lines and there could be a various amount of .txt files.
Here is the code that I have tried;
static void WriteToFile(string directory, string name)
{
string filename = String.Format(name);
string path = Path.Combine(directory, filename);
using (StreamWriter sw = File.CreateText(path))
{
sw.WriteLine("Inserted Text");
}
}
......
string[] allFiles = Directory.GetFiles(folder, "*.txt");
foreach (string file in allFiles)
{
string[] lines = File.ReadAllLines(file);
foreach (string newfile in lines)
{
WriteToFile(folder, newfile);
}
}
This is now creating the files but I need to specify the extension as they are just created as 'file1' instead of 'file1.ext'
File.Create Method (String) returns FileStream. The FileStream must be disposed to flush file. Try using this code to create an empty file:
File.Create(fileName).Dispose();
Also, take a look at the similar question: Creating an empty file in C#.
Without any details of error/exception, to me it seems either permission issue, or character issue.
You can use Path.GetInvalidPathChars with Enumerable.Intersect to check if file path contains invalid characters before creating new file
char[] invalidPathChars = Path.GetInvalidPathChars();
foreach (string newfile in lines)
{
if (invalidPathChars.Intersect(newfile).Any())
{
Console.WriteLine(newfile + " contains invalid characters for file name");
continue;
}
File.Create(newfile);
}
File.Create returns a filestream that you can use to write to the new file. But you are not providing the path that is the argument in Create but the line. The line might be an invalid path.
You can use this query instead:
string invalidCharacters = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
var allPaths = Directory.EnumerateFiles(folder, "*.txt")
.SelectMany(path => File.ReadLines(path))
.Select(line => {
string fileName = line;
foreach (Char c in invalidCharacters)
fileName = fileName.Replace(c.ToString(), "_");
return new{ line, path = Path.Combine(targetFolder, fileName) };
} );
foreach(var p in allPaths)
{
File.WriteAllText(p.path, p.line);
}
Edit: however, that will very likely result in this error:
The specified path, file name, or both are too long. The fully
qualified file name must be less than 260 characters, and the
directory name must be less than 248 characters.
So you need to use a method that shortens the path (f.e. using a logic that appends a number to avoid duplicate names).
static void WriteToFile(string directory, string name)
{
string filename = String.Format(name + ".ini");
string path = Path.Combine(directory, filename);
using (StreamWriter sw = File.CreateText(path))
{
sw.WriteLine("Inserted Text");
}
}
......
var allFiles = Directory.GetFiles(folder, "*.txt");
foreach (string file in allFiles)
{
var lines = File.ReadAllLines(file);
foreach (string newfile in lines)
{
WriteToFile(folder, newfile);
}
}
Is it possible to read files from a directory one file after another?
I look for something like:
while (File file = Directory.GetFile(path)) {
//
// Do something with file
//
}
[UPDATE]
I already knew about GetFiles() but I'm looking for a function that return one file at a time.
EnumerateFiles() is .Net4.x, would be nice to have, but I'm using .Net2.0. Sorry, that I didn't mention.
(Tag updated)
You can enumerate over the file names:
foreach(string fileName in Directory.EnumerateFiles(path)) {
// Do something with fileName - using `FileInfo` or `File`
}
string[] arFiles = Directory.GetFiles(#"C:\");
foreach (var sFilename in arfiles)
{
// Open file named sFilename for reading, do whatever
using (StreamReader sr = File.OpenText(sFilename ))
{
string s = "";
while ((s = sr.ReadLine()) != null)
{
Console.WriteLine(s);
}
}
}
foreach (var file in Directory.EnumerateFiles(path))
{
var currFileText = File.ReadAllText(file);
}
What about Directory.GetFiles(path) method?
foreach(String fileName in Directory.GetFiles(path))
{
FileInfo file = new FileInfo(fileName);
}
Try with this...
foreach (var filePath in Directory.GetFiles(path))
{
var text = File.ReadAllText(filePath);
// Further processing
}