I'm trying to replace a file line with another one.
here's my block of code
string text = readWholeFile(fileName);
text = text.Replace(oldLine, newLine);
IsolatedStorageFile myStore = IsolatedStorageFile.GetUserStoreForApplication();
using (var isoFileStream = new IsolatedStorageFileStream(fileName,
FileMode.OpenOrCreate, FileAccess.Write, myStore))
{
using (var isoFileWriter = new StreamWriter(isoFileStream))
{
isoFileWriter.WriteLine(text);
isoFileWriter.Close();
}
isoFileStream.Close();
the problem is that the Line is only replaced the exact number of newLine characters.For example if OldLine was 1234567890 and newLine is asd. The file operation gives output something like this
asd
4567890
here readWholeFile method reads the whole file. and oldLine ,newLine is the method string parameter.
This piece of code works as expected:
string text = "1234567890\n1234567891\n1234567892";
var rText = text.Replace("1234567890", "asd");
Console.WriteLine(rText);
Console.ReadKey();
The output is:
asd
1234567891
1234567892
So, it's obvious that you're problem isn't with the String.Replace method.
You can use a simple code to "read the whole file":
string[] text = File.ReadAllLines(filename);
StringBuilder str = new StringBuilder();
foreach (string s in text)
str.AppendNewLine(s);
And than,
var rText = str.ToString().Replace(oldLine, newLine);
And finally, save everything to file again:
File.WriteAllText(outputFile, rText);
EDIT
Also, the following code works:
string text = "1234567890\n1234567891\n1234567892";
var rText = text.ToString().Replace("1234567890", "asd");
using (var isoFileStream = new FileStream("output.txt",
FileMode.Create, FileAccess.Write))
{
using (var isoFileWriter = new StreamWriter(isoFileStream))
{
isoFileWriter.Write(rText);
}
}
The output, as expected, was:
asd
1234567891
1234567892
But I found that the following caused problems:
using (var isoFileStream = new FileStream("output.txt",
FileMode.OpenOrCreate, FileAccess.Write))
{
using (var isoFileWriter = new StreamWriter(isoFileStream))
{
isoFileWriter.Write(rText);
}
}
The situation that this caused problems was when the file already exists with the following content:
1234567890
1234567891
1234567892
The output in the file was:
asd
1234567891
1234567892
67892
If instead of File.OpenOrCreate the file mode is changed to File.Create, the problem disappears.
EDIT
I didn't used "IsolatedStorageFile" just because I'm not testing on a SilverLight context nor using ClickOnce to deploy, and so it won't work
Related
I have a method that writing a csv from list content. If the csv file size reach to specific size like 5MB, I want to create a new csv file so it won't grow too big if the list content is huge. Here is my code below but it is not working. I am getting error "file is being used by another process". Looks like this is not the correct way to create the new csv file.
public static void WriteCSV<T>(IEnumerable<T> items, string path)
{
Type itemType = typeof(T);
var props = itemType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.OrderBy(p => p.Name);
int filenumber = 0;
using (var writer = new StreamWriter(path))
{
writer.WriteLine(string.Join(", ", props.Select(p => p.Name)));
foreach (var item in items)
{
writer.WriteLine(string.Join(", ", props.Select(p => p.GetValue(item, null))));
if (writer.BaseStream.Length > 5120)
{
writer.Close();
writer.Dispose();
filenumber++;
var writer2 = new StreamWriter(string.Format(path, filenumber), false);
}
}
}
}
Your problem is two-fold.
The method string.Format(path, filenumber) does not do what you expect it to. It actually expects a format string as the first argument like "value goes here {0}" and a variable to put into the place of the {0}. Since you give it only a path it will return simply the path, which is the same name as your previous file. Hence your get the error, because you are trying to access the same file again.
Solution to 1):
1.1) you need to break the path into the path and the filename,
1.2) then take the filename without extension,
1.3) then concatenate the number to the filename
1.4) reconstruct the path.
Problem 2)
The iteration over the collection should not be inside the using block of the writer. It even does not depend on the writer. This makes it impossible for you to use another writer without specifying a new instance each time. This would make the code ugly and unnecessarily complicated.
Remove the using block and dispose the writer by hand as you already do:
Here is an examplary programm that does the trick.
void Main()
{
string path = #"C:\WorkSpace\temp\test\fileName.csv";
List<string> items = Enumerable.Range(1, 1200).Select(x => $"Something: {x} else {x+2} ").ToList();
int filenumber = 0;
var writer = new StreamWriter(path);
string pathOnly = Path.GetDirectoryName(path);
string fileName = Path.GetFileNameWithoutExtension(path);
string extension = Path.GetExtension(path);
foreach (var item in items)
{
writer.WriteLine(string.Join(", ", item.Split(' ')));
if (writer.BaseStream.Length > 120)
{
writer.Close();
writer.Dispose();
filenumber++;
writer = new StreamWriter(Path.Combine(pathOnly, $"{fileName}{filenumber}{extension}"), false);
}
}
// don't forget to close and dispose the last instance of the writer
writer.Close();
writer.Dispose();
}
I need to check if the string exists in a text file and if it does then proceed. if not, it will display a MessageBox saying that the ID does not exist.
In my previous question, I tried to check if "testfile.txt" contains the string inputted by the user in TextBox1 then copy the line which contains the string into a new textfile. Using the approach that has been suggested, here's a snippet of what I have so far:
string emp_profile = #"EmployeeData.txt"; //file to be checked
string endata = #"EndData.txt"; //terminated employees data file
string end_tdata = #"end_tdata.txt"; //holds sample's data
//validates if eid exists and if it exists copies data of sample
//plus txt_end.Text into temporary data file
string[] dataline = File.ReadAllLines(emp_profile);
using (StreamWriter w = File.AppendText(end_tdata))
{
foreach (var line in dataline)
{
if (line.Contains(txt_un.Text))
{
w.WriteLine(txt_end.Text + "," + line);
w.Close();
}
}
}
string end_holddata = #"end_holddata.txt";
//read original file
string[] raw_data = File.ReadAllLines(endata);
using (StreamWriter r = File.AppendText(end_holddata))
{
foreach (var line in raw_data)
{
if (!line.Contains(txt_un.Text))
r.WriteLine(line);
}
r.Close();
}
//delete original file
File.Delete(endata);
//creates new data file with old data path
//and copies the temporary data held testdata
using (Stream input = File.OpenRead(end_holddata))
using (Stream output = new FileStream(endata, FileMode.Append,
FileAccess.Write, FileShare.None))
{
input.CopyTo(output);
}
//appends new data of sample into the newly created data file
using (Stream input = File.OpenRead(end_tdata))
using (Stream output = new FileStream(endata, FileMode.Append,
FileAccess.Write, FileShare.None))
{
input.CopyTo(output);
}
DialogResult result = MessageBox.Show("Data has been recorded.");
//clears all temporary files
if (result == DialogResult.OK)
{
File.Delete(end_holddata);
File.Delete(end_tdata);
}
What I'm trying to do here is that I'm copying the data from the "emp_profile.txt that does not contain the txt_un.Text into "end_holddata" and copy the line that contains the input into a different file end_tdata.txt, delete the old datafile to clear contents then merge the data into a new data with the same pathfile as the old one. Afterwards, the temporary data files would be deleted.
I tried enclosing the above snippet within this but it's not working the way I want it to.
string[] dataline = File.ReadAllLines(emp_profile);
for (int i = 0; i < dataline.Length; i++)
{
if (dataline[i].Contains(txt_un.Text))
{
//code snippet here
}
else
MessageBox.Show("ID does not exist!");
}
Any help would appreciated! Thank you in advance!
I'm trying to remove any "new line" characters from each line of text in my log file.
Below is an example entry that I am reading in with a Stream Reader :-
<![LOG[Raising event:
[SMS_CodePage(850), SMS_LocaleID(2057)]
instance of SoftDistProgramStartedEvent
{
AdvertisementId = "000216F6";
ClientID = "GUID:B55C2757-CBAE-468E-B54F-46CAF2ECF68F";
CommandLine = "\"C:\\WINNT\\system32\\cscript.exe\" /nologo Shutdown_Desktops_Overnight.vbs";
DateTime = "20130211080211.784000+000";
MachineName = "DWD*****";
PackageName = "0000073C";
ProcessID = 2516;
ProgramName = "Shutdown Desktops Overnight";
SiteCode = "S00";
ThreadID = 3640;
UserContext = "NT AUTHORITY\\SYSTEM";
WorkingDirectory = "C:\\WINNT\\system32\\CCM\\Cache\\0000073C.1.System\\";
};
]LOG]!><time="08:02:11.800+000" date="02-11-2013" component="execmgr" context="" type="1" thread="3640" file="event.cpp:522">
In the actual Logfile this is displayed as one line in the file, with the "New Line Characters" replaced with a square.
I'm using the following code to read in the log entries :-
using (StreamReader sr = new StreamReader(#"C:\Documents and Settings\riversd\Desktop\Logfile2.log"))
{
string Line;
while ((Line = sr.ReadLine()) != null)
{
}
}
The issue is that when the StreamReader reads this entry from the txt file it breaks at :-
"<![LOG[Raising event:"
I need to remove all new line characters in this entry, on the fly. I don't want to read the entire file into memory and then remove them, I'd rather deal with each log as I read it.
Is it possible?
The call to Replace isn't working because of this detail from the MSDN doc of StreamReader.ReadLine:
A line is defined as a sequence of characters followed by a line feed ("\n"), a carriage return ("\r"), or a carriage return immediately followed by a line feed ("\r\n"). The string that is returned does not contain the terminating carriage return or line feed.
So if you're going to use StreamReader.ReadLine to read in the input, you could build up a new string with StringBuilder.Append (not AppendLine) as StreamReader.ReadLine implicitly removes the new line characters.
var filePath = "text.txt";
StringBuilder sb = new StringBuilder();
using (StreamReader reader = new StreamReader(filePath))
{
while (!reader.EndOfStream)
{
sb.Append(reader.ReadLine());
}
}
File.WriteAllText(filePath, sb.ToString());
sr.ReadLine().Replace(Environment.NewLine, String.Empty);
EDIT:
In case the end of line is not \r\n but \n you can use regex:
Line = Regex.Replace(sr.ReadLine(), #"(\r\n|\n)", String.Empty);
i dont know if anyone else was having exactly this issue.
here is the code i used to fix this issue.
using (System.IO.FileStream File = new System.IO.FileStream(e.FullPath, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite))
{
using (System.IO.StreamReader Reader = new System.IO.StreamReader(File, Encoding.Default))
{
String CompleteData = Reader.ReadToEnd();
foreach (String Line in CompleteData.Split(new char[] { (char)13 }, StringSplitOptions.RemoveEmptyEntries))
{
if (Line.Split(new String[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)[0].Contains("Raising event"))
{
//Do Stuff
}
}
Reader.Close();
}
File.Close();
}
For some reason i had to do this because just using streamreader would throw an exception saying that the file is in use from another process.
It might help someone else at a later date..
I am making a project that uses streamreader and streamwriter, Is it possible that I only replace or save a text in an specific line only without affecting the other lines?
if I make like this
streamreader sr = new streamreader(#"txtfile");
list<string> lines = new list<string>();
while (!sr.EndOfStream)
sr.readline();
{
lines.Add(sr.ReadLine();
}
//put in textbox
sr.close();
{
streamwriter sw = new streamwriter(#"txtfile");
sw.WriteLine(textBox1.text);
sw.close();
}
this is just a sample, but Is it possible that I use list also un streamwriter?
If you want a one line solution (code golf :) ) you can use
string path = #"C:\Test.txt";
string lineToReplace = "Relpace This Line";
string newLineValue = "I Replaced This Line";
File.WriteAllLines(path, File.ReadAllLines(path).Select(line => line.Equals(lineToReplace) ? newLineValue : line));
You cannot just change a line as such but you can to ReadAllLines, find the line you want to change, change it and write all of it to the file again :
StringBuilder newFile = new StringBuilder();
string temp = "";
string[] file = File.ReadAllLines(#"txtfile");
foreach (string line in file)
{
if (line.Contains("string you want to replace"))
{
temp = line.Replace("string you want to replace", "New String");
newFile.Append(temp + "\r\n");
continue;
}
newFile.Append(line + "\r\n");
}
File.WriteAllText(#"txtfile", newFile.ToString());
Read the file into memory, changing the line(s) you want to change, close the reader, open the file for writing, write the new contents of the file out.
I am new to C#. How can I write data into one file? This is my code so far:
public void convertHTML(string strData, string strTitle)
{
int position = strTitle.LastIndexOf('.');
strTitle = strTitle.Remove(position);
strTitle= strTitle + ".html";
StreamWriter sw = new StreamWriter(strTitle); //strTitle is FilePath
sw.WriteLine("<html>");
sw.WriteLine("<head><title>{0}</title></head>",strTitle);
//MessageBox.Show("this editor");
sw.WriteLine("<body>");
sw.WriteLine(strData); //strData is having set of lines
sw.WriteLine("</body>");
sw.WriteLine("</html>");//*/
lstHtmlFile.Items.Add(strTitle);
}
it will simply create one blank html file it won't have any data
You need to flush and close the StreamWriter:
using (StreamWriter sw = new StreamWriter(strTitle))
{
sw.WriteLine("<html>");
sw.WriteLine("<head><title>{0}</title></head>",strTitle);
sw.WriteLine("<body>");
sw.WriteLine(strData);
sw.WriteLine("</body>");
sw.WriteLine("</html>");
}
Using using does the trick.
You can add block using in order to clean your non managed object
using (var streamWriter = new StreamWriter(strTitle))
{
....
}
Link : http://msdn.microsoft.com/fr-fr/library/vstudio/yh598w02.aspx