At runtime, I want to read all files who has the time stamp of a particular time. For example: if the application is running at 11:00:--, then it should read all files which is created after 11:00:00 till now(excluding the present one) and must write in the present file..I have tried like:
string temp_file_format = "ScriptLog_" + DateTime.Now.ToString("dd_MM_yyyy_HH");
string path = #"C:\\ScriptLogs";
var all_files = Directory.GetFiles(path, temp_file_format).SelectMany(File.ReadAllLines);
using (var w = new StreamWriter(logpath))
foreach (var line in all_files)
w.WriteLine(line);
But, this doesn't seems to be working.No error..No exception..But it doesn't read the files, while it exist.
The pattern parameter of the GetFiles method should probably also include a wildcard, something like:
string temp_file_format = "ScriptLog_" + DateTime.Now.ToString("dd_MM_yyyy_HH") + "*";
This will match all files starting with "ScriptLog_13_09_2013_11"
As #Edwin already solved your problem, I'd just like to add a suggestion regarding your code (mostly performance related).
Since you are only reading these lines in order to write them to a different file and discard them from memory, you should consider using File.ReadLines instead of File.ReadAllLines, because the latter method loads all lines from each file into memory unnecessarily.
Combine this with the File.WriteAllLines method, and you can simplify your code while reducing memory pressure to:
var all_files = Directory.GetFiles(path, temp_file_format);
// File.ReadLines returns a "lazy" IEnumerable<string> which will
// yield lines one by one
var all_lines = all_files.SelectMany(File.ReadLines);
// this iterates through all_lines and writes them to logpath
File.WriteAllLines(logpath, all_lines);
All that can even be written as a one-liner (that is, if you are not paid by your source code line count). ;-)
Related
I'm doing a little program where the data saved on some users are stored in a text file. I'm using Sytem.IO with the Streamwriter to write new information to my text file.
The text in the file is formatted like so :
name1, 1000, 387
name2, 2500, 144
... and so on. I'm using infos = line.Split(',') to return the different values into an array that is more useful for searching purposes. What I'm doing is using a While loop to search for the correct line (where the name match) and I return the number of points by using infos[1].
I'd like to modify this infos[1] value and set it to something else. I'm trying to find a way to replace a word in C# but I can't find a good way to do it. From what I've read there is no way to replace a single word, you have to rewrite the complete file.
Is there a way to delete a line completely, so that I could rewrite it at the end of the text file and not have to worried about it being duplicated?
I tried using the Replace keyword, but it didn't work. I'm a bit lost by looking at the answers proposed for similar problems, so I would really appreciate if someone could explain me what my options are.
If I understand you correctly, you can use File.ReadLines method and LINQ to accomplish this.First, get the line you want:
var line = File.ReadLines("path")
.FirstOrDefault(x => x.StartsWith("name1 or whatever"));
if(line != null)
{
/* change the line */
}
Then write the new line to your file excluding the old line:
var lines = File.ReadLines("path")
.Where(x => !x.StartsWith("name1 or whatever"));
var newLines = lines.Concat(new [] { line });
File.WriteAllLines("path", newLines);
The concept you are looking for is called 'RandomAccess' for file reading/writing. Most of the easy-to-use I/O methods in C# are 'SequentialAccess', meaning you read a chunk or a line and move forward to the next.
However, what you want to do is possible, but you need to read some tutorials on file streams. Here is a related SO question. .NET C# - Random access in text files - no easy way?
You are probably either reading the whole file, or reading it line-for-line as part of your search. If your fields are fixed length, you can read a fixed number of bytes, keep track of the Stream.Position as you read, know how many characters you are going to read and need to replace, and then open the file for writing, move to that exact position in the stream, and write the new value.
It's a bit complex if you are new to streams. If your file is not huge, copying a file line for line can be done pretty efficiently by the System.IO library if coded correctly, so you might just follow your second suggestion which is read the file line-for-line, write it to a new Stream (memory, temp file, whatever), replace the line in question when you get to that value, and when done, replace the original.
It is most likely you are new to C# and don't realize the strings are immutable (a fancy way of saying you can't change them). You can only get new strings from modifying the old:
String MyString = "abc 123 xyz";
MyString.Replace("123", "999"); // does not work
MyString = MyString.Replace("123", "999"); // works
[Edit:]
If I understand your follow-up question, you could do this:
infos[1] = infos[1].Replace("1000", "1500");
was hoping for some advice as to how to convert existing file names in a folder...all to lower case.
I felt that a good start would be to save the file names in a list and convert them all to lower.
How can I replace the existing file names in the folder to the lower case ones?
List<string> codes = new List<string>();
string[]productCodes = Directory.GetFiles(#"C:\Users\Ariang\Desktop\screenshotslowercase\screenshots");
codes = productCodes.ToList();
codes = codes.ConvertAll(t => t.ToLower());
This should work:
foreach (var file in Directory.GetFiles(#"C:\Temp\testrename"))
{
File.Move(file, file.ToLowerInvariant());
}
A few notes, first of all I have tested this and it works, somebody else mentioned using a temporary variable, but I haven't needed to do this.
Also, I have run this multiple times on the same directory, and I don't get an IOException the second or third time around, so I don't think any additional checking is necessary.
However, I am on Windows 8 and targeting .Net 4.5, things may be different on earlier versions of Windows or .Net.
Windows system doesn't see difference betweeen lower and upper letters in file names. Thats why you can't convert like "MyFile" -> "myfile". Use two steps instead:
foreach (var file in Directory.GetFiles(#"C:\Temp\testrename"))
{
var tempName = "." + file.ToLowerInvariant();
File.Move(file, tempName);
File.Move(tempName, file.ToLowerInvariant());
}
no need for list and all that. Simple read the file name from directory and use
System.IO.File.Move("oldfilename", "oldfilename".ToLower());
string[] files = Directory.GetFiles(dir);
foreach(string file in files)
{
System.IO.File.Move(file, file.ToLowerInvariant());
}
I am creating an application which converts a MS Access table and an Excel sheet to .csv files and then differences the access table with the excel sheet. The .csv files are fine but the resulting difference file has errors in fields that contain html (the access table has fields with the html). I'm not sure if this is a special character issue because the special characters were not an issue in creating the .csv file in the first place, or if it is an issue with the way I am differencing the two files.
Part of the problem I suppose could be that in the access .csv file, the fields that contain the html are formatted so that some of the information is on separate lines instead of all on one line, which could be throwing off the reader, but I don't know how to correct this issue.
This is the code for creating the difference file:
string destination = Form2.destination;
string path = Path.Combine(destination, "en-US-diff.csv");
string difFile = path;
if (File.Exists(difFile))
{
File.Delete(difFile);
}
using (var wtr = new StreamWriter(difFile))
{
// Create the IEnumerable data sources
string[] access = System.IO.File.ReadAllLines(csvOutputFile);
string[] excel = System.IO.File.ReadAllLines(csvOutputFile2);
// Create the query
IEnumerable<string> differenceQuery = access.Except(excel);
// Execute the query
foreach (string s in differenceQuery)
{
wtr.WriteLine(s);
}
}
Physical line versus logical line. One solution is to use a sentinel, which is simply an arbitrary string token selected in such a way so as not to confound the parsing process, for example "##||##".
When the input files are created, add the sentinel to the end of each line...
1,1,1,1,1,1,###||##
Going back to your code, the System.IO.File.ReadAllLines(csvOutputFile); uses the Environment.Newline string as its sentinel. This means that you need to replace this statement with the following (pseudo code)...
const string sentinel = "##||##";
string myString = File.ReadAllText("myFileName.csv");
string[] access = myString.Split(new string[]{sentinel},
StringSplitOptions.RemoveEmptyEntries);
At that point you will have the CSV lines in your 'access' array the way you wanted as a collection of 'logical' lines.
To make things further conformant, you would also need to execute this statement on each line of your array...
line = line.Replace(Environment.NewLine, String.Empty).Trim();
That will remove the culprits and allow you to parse the CSV using the methods you have already developed. Of course this statement could be combined with the IO statements in a LINQ expression if desired.
FileName="1.pdf",filepath="f:/test1"
FileName="2.pdf",filepath="f:/test2"
FileName="3.pdf",filepath="f:/test3"
FileName="4.pdf",filepath="f:/test4"
FileName="5.pdf",filepath="f:/test5"
FileName="6.pdf",filepath="f:/test6"
I don't want to create a new file. Overwriting in a same file is ok
I tried the following.
var reader = File.OpenText("f:/test5");
reader. // ?
I don't know what to put after reader. If any alternate way is there, provide me a solution.I want to remove only a particular line based on the unique file name. If I am having 5.pdf as the filename, then I need to delete or remove the entire line which is "FileName="5.pdf"...line from the file. I don't want to overwrite the contents in a new file again. Provide me a solution. Thanks.
You cannot reomve a line from a textfile without rewriting the file. Do something like this
string filename =
Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory),
"Test1.txt");
string[] lines = File.ReadAllLines(filename);
var list = new List<string>(lines);
list.RemoveAt(4);
File.WriteAllLines(filename, list.ToArray());
EDIT:
You can find a line with a specific filename like this:
int index = list.FindIndex(s => s.EndsWith("/test5\""));
// Or whatever test is appropriate.
if (index >= 0) {
list.RemoveAt(index);
File.WriteAllLines(filename, list.ToArray());
}
If you don't mind using gnu tools, you can use sed http://en.kioskea.net/faq/1451-sed-delete-one-or-more-lines-from-a-file
It's technically impossible, as much as I'm aware of, as OS will create a new IO artifact.(By the way not very sure on this) .
But what is much more important, that it's extremely dangerous. IO operations are subjects to fail, so you have to gurantee in some way consistency of your operations on file.
One of possible ways of doing this is:
write all lines, except those ones you want to skip, into the new TEMP file
rename your old file with some other temp name
rename fisrt TEMP file in name of previous file
delete original file.
No matter what utility you use or what code you write, the operating system will always create a new file to do it.
Using LINQ, what is an efficent way to get each string from a tab-delimited .txt file (and then get each word, usually what string.Split(...) does)?
var v = from line in File.ReadAllLines()
select n
Is part of this solution I believe. I don't mind if this uses yield return.
EDIT: I've also seen threads on here detailing exactly what I am trying to do, but can't find them.
I'm not entirely sure what you're asking but it sounds like you're trying to get every word from a tab delimited file as an IEnumerable<string>. If so then try the following
var query = File.ReadAllLines(somePathVariable)
.SelectMany(x => x.Split(new char[] { '\t' });
Using File.ReadAllLines is easy - but not necessarily the most efficient, since it reads the entire line into memory.
A short version would probably be:
var wordsPerLine = from line in File.ReadAllLines(filename)
select string.Split(line, '\t');
foreach(var line in wordsPerLine)
{
foreach(word in line)
{
// process word...
}
}
If you want a single enumerable of the words, you can use SelectMany to get that, too...