How can I write and read a text doucument in a folder? - c#

string curetn = Environment.CurrentDirectory;
string path = curetn.ToString() + #"\DATA\SaveGame.txt";
Console.WriteLine(path);
TextReader tr = new StreamReader(path);
Hello, I am making a text-adventure, and I do not like having all my save files, and mp3 file in the same place as my application. I would like for the files to be in a folder. I want to be able to use StreamWriter and StreamReader, to be able to write and read files that are in a folder. This file is also in a distributable folder, not just in the Visual Studios Projects folders. I have tried everything I can, and this is what I have. I also have one of these for StreamWriter. Please help!
Edit:
The thing that does not work, is that it does not read the lines, and assigns them to a variable. I have it in a try-catch, and it catches, and displays the error message that I wrote.

If you are looking for simply read and write lines from file you can try this
using (StreamReader sr = new StreamReader(path))
{
while (!sr.EndOfStream)
{
sr.ReadLine();
}
}
string s;
using (StreamWriter sw = new StreamWriter(path))
{
sw.WriteLine(s);
}

So basically what you want to do is read the text file:
string data[] = File.ReadAllLines(path); // Read the text file.
var x = data[1]; // Replace the '1' with the line number you want.
Console.WriteLine(x);
This is a good way to read the text file, I think it's better than opening a stream.
You can also write to it, so every time you want to save, just do this:
// When you want to write:
File.WriteAllText(path, "");
File.AppendAllText(path, "Add a data line" + Environment.NewLine); // Environment.NewLine adds a line.
Keep appending text to the file for the data you need.

Related

StreamWriter adds extra character(s) on new line(s) at the end of file

I'm trying to modify an .ini file, in C# with .NET 5.0, using FileStream and StreamReader / StreamWriter. I just need to modify the first line of the file so I read the entire file into a list of strings called strList, modify the first line, and then write it all back to the same file.
List<string> strList = new List<string>();
using (FileStream fs = File.OpenRead(#"C:\MyFolder\test.ini"))
{
using (StreamReader sr = new StreamReader(fs))
{
while (!sr.EndOfStream)
{
strList.Add(sr.ReadLine());
}
}
}
strList[0] = "test01";
using (FileStream fs = File.OpenWrite(#"C:\MyFolder\test.ini"))
{
using (StreamWriter sw = new StreamWriter(fs))
{
for (int x = 0; x < ewsLines.Count; x++)
{
sw.WriteLine(strList[x]);
}
}
}
The issue I'm running into is that I'll have new character(s) at the end of my file on new line(s). I verified that the number of lines I read from the file matches what is in the file and that the for loop only writes that same number of lines back into the file. I don't have any issues writing other strings except for "test01". This string is the only one that causes the issue that I just described. It seems to be grabbing characters from the last line like R or LAYER from MULTI_LAYER.
Ex 1: This
S10087_U1
Cq4InEq=TRUE
XtrVer=5.5
IOCUPDATEMDB=TRUE
ARCHITECTURE=MULTI_LAYER
Becomes this
test01
Cq4InEq=TRUE
XtrVer=5.5
IOCUPDATEMDB=TRUE
ARCHITECTURE=MULTI_LAYER
R
Ex 2: This
test01 - Copy
Cq4InEq=TRUE
XtrVer=5.5
IOCUPDATEMDB=TRUE
ARCHITECTURE=MULTI_LAYER
ER
Becomes this
test01
Cq4InEq=TRUE
XtrVer=5.5
IOCUPDATEMDB=TRUE
ARCHITECTURE=MULTI_LAYER
LAYER
Replacing the StreamWriter portion with the following seems to fix the issue but I'm trying to figure out why using StreamWriter doesn't work as I expect it to.
File.WriteAllLines(#"C:\MyFolder\test.ini", strList);
This is because you're using File.OpenWrite. From the remarks in the documentation:
The OpenWrite method opens a file if one already exists for the file path, or creates a new file if one does not exist. For an existing file, it does not append the new text to the existing text. Instead, it overwrites the existing characters with the new characters. If you overwrite a longer string (such as "This is a test of the OpenWrite method") with a shorter string (such as "Second run"), the file will contain a mix of the strings ("Second runtest of the OpenWrite method").
While you could just change your code to use File.Create instead, I'd suggest changing the code more significantly - not just the writing, but the reading too:
string path = #"C:\MyFolder\test.ini";
var lines = File.ReadAllLines(path);
lines[0] = "test01";
File.WriteAllLines(path, lines);
That's much simpler code to do the same thing.
The half-way house between the two would be to use File.OpenText (to return a StreamWriter) and File.CreateText (to return a StreamWriter). There's no need to do the wrapping yourself.

Replace one specific line in a huge text file

I want to replace one specific line in a text file. The simplest solution would be:
public void ModifyFile(string path, int line, string targetText) {
var lines = File.ReadAllLines(path);
lines[line] = targetText;
File.WriteAllLines(path, lines);
}
The thing is, if the file is huge enough, I will get a System.OutOfMemoryException because File.ReadAllLines() tries to load the whole file in memory, instead of a line-by-line way.
I know there is another way to read a specific line with less memory cost:
var line = File.ReadLines(path).Skip(line-1).Take(1).ToString();
How can I replace over that line in the file?
I'm looking for something like FileStream.Write Method:
var writer = File.OpenWrite(path);
writer.Write(Encoding.UTF8.GetBytes(targetText),
offset, Encoding.UTF8.GetByteCount(targetText));
But it's difficult to know offset.
Is there a better way to do that?
-- UPDATE --
The temporary file solution suggested by answers works great.
At the same time, I am wondering, is there a specific case solution without creating a temporary file, if I know line is a small number (line < 100 let's say)? There must be a better solution if I want to change the 10th line in a text file having 100m lines.
You could just read the file a line at a time using streams, and copy the contents into a new file, or rename the old file with a backup name and then process with;
string line;
int couinter = 0;
// Read the file and display it line by line.
System.IO.StreamReader reader = new System.IO.StreamReader(path);
System.IO.StreamWriter writer = new System.IO.StreamWriter(new_path);
while((text = reader.ReadLine()) != null)
{
// Check for your content and replace if required here
if ( counter == line )
text = targetText;
writer.writeline(text);
counter++;
}
reader.Close();
writer.Close();
What you can do is open the FileStrem with StreamReader (which provides ReadLine method). Now read line by line and write the output to a temporary file line by line. When you are on the desired line just change the line.

Find regex in file with StreamReader and overwrite it with StreamWriter

I am reading text file with StreamReader and doing Regex.Match to find specific info, now when I found it I want to replace it with Regex.Replace and I want to write this replacement back to the file.
this is text inside my file:
///
/// <Command Name="Press_Button" Comment="Press button" Security="Security1">
///
/// <Command Name="Create_Button" Comment="Create button" Security="Security3">
/// ... lots of other Commands
now I need to find : Security="Security3"> in Create_Button command, change it to Security="Security2"> and write it back to the file
do {
// read line by line
string ReadLine = InfoStreamReader.ReadLine();
if (ReadLine.Contains("<Command Name"))
{
// now I need to find Security1, replace it with Security2 and write back to the file
}
}
while (!InfoStreamReader.EndOfStream);
any ideas are welcome...
EDITED:
Good call was from tnw to read and write to the file line by line. Need an example.
I'd do something more like this. You can't directly write to a line in the file like you're describing there.
This doesn't use regex but accomplishes the same thing.
var fileContents = System.IO.File.ReadAllText(#"<File Path>");
fileContents = fileContents.Replace("Security1", "Security2");
System.IO.File.WriteAllText(#"<File Path>", fileContents);
Pulled pretty much directly from here: c# replace string within file
Alternatively, you could loop thru and read your file line-by-line and write it line-by-line to a new file. For each line, you could check for Security1, replace it, and then write it to the new file.
For example:
StringBuilder newFile = new StringBuilder();
string temp = "";
string[] file = File.ReadAllLines(#"<File Path>");
foreach (string line in file)
{
if (line.Contains("Security1"))
{
temp = line.Replace("Security1", "Security2");
newFile.Append(temp + "\r\n");
continue;
}
newFile.Append(line + "\r\n");
}
File.WriteAllText(#"<File Path>", newFile.ToString());
Source: how to edit a line from a text file using c#

Writing a Text File in memory and saving it with savefiledialog

I am trying to make a text file in memory, add some lines to it and at the end save the file in a text file. I can handle the savedialog part but I dont know how to get the text file from memory. Any help and tips will be appriciated.
What I am doing so far is:
//Initialize in memory text writer
MemoryStream ms = new MemoryStream();
TextWriter tw = new StreamWriter(ms);
tw.WriteLine("HELLO WORLD!");
tw.WriteLine("I WANT TO SAVE THIS FILE AS A .TXT FILE!);
please note
I will call tw.WriteLine() add more lines in different places so I want to save this at end of program (so this shouldent be wrapped between something like using{} )
UPDATE
StringBuilder seems to be a more reliable option for doing this! I get strange cut-outs in my text file when I do it using MemoryStream.
Thanks.
I think your best option here would be to write to a StringBuilder, and when done, File.WriteAllText. If the contents are large, you might consider writing directly to the file in the first place (via File.CreateText(path)), but for small-to-medium files this should be fine.
var sb = new StringBuilder();
sb.AppendLine("HELLO WORLD!");
sb.AppendLine("I WANT TO SAVE THIS FILE AS A .TXT FILE!");
File.WriteAllText(path, sb.ToString());
Or, something nigh-on the same as #Marc's answer, but different enough that I think it's worth putting out there as a valid solution:
using (var writer = new StringWriter())
{
writer.WriteLine("HELLO WORLD!");
writer.WriteLine("I WANT TO SAVE THIS FILE AS A .TXT FILE!");
File.WriteAllLines(path, writer.GetStringBuilder().ToString());
}
Where path is a string representing a valid file system entry path, predefined by you somewhere in the application.
Assume your SaveFileDialog name is "dialog"
File.WriteAllBytes(dialog.FileName, Encoding.UTF8.GetBytes("Your string"));
or
var text = "Your string";
text += "some other text";
File.WriteAllText(dialog.FileName, text);
also in your own solution you can do this :
MemoryStream ms = new MemoryStream();
TextWriter tw = new StreamWriter(ms);
tw.WriteLine("HELLO WORLD!");
tw.WriteLine("I WANT TO SAVE THIS FILE AS A .TXT FILE!);
// just add this
File.WriteAllBytes(dialog.FileName, ms.GetBuffer());
Something like this.
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".text"; // Default file extension
dlg.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension
// Show save file dialog box
Nullable<bool> result = dlg.ShowDialog();
// Process save file dialog box results
if (result == true)
{
// Save document
using (FileStream file = File.CreateText(dlg.FileName)
{
ms.WriteTo(file)
}
}
I haven't worried about whether the file already exists but this should get you close.
You might need a ms.Seek(SeekOrgin.Begin, 0) too.
Another way of appending text to the end of a file could be:
if (saveFileDialog.ShowDialog() == DialogResult.OK) {
using (var writer = new StreamWriter(saveFileDialog.Filename, true)) {
writer.WriteLine(text);
}
}
supposing that text is the string you need to save into your file.
If you want to append new lines to that string in an easy way, you can do:
var sb = new StringBuilder();
sb.AppendLine("Line 1");
sb.AppendLine("Line 2");
and the resulting string will be sb.ToString()
If you already have a Stream object (in your example, a MemoryStream), you can do the same but replace the line:
using (var writer = new StreamWriter(saveFileDialog.Filename, true)) {
by
using (var writer = new StreamWriter(memoryStream)) {
Edit:
About wrapping the statements inside using:
Take in count that this is not a problem at all. In my first example, all you will have to do is to keep that StringBuilder object, and keep adding lines to it. Once you have what you want, just write the data into a text file.
If you are planning to write more than once to the text file, just clear the StringBuilder everytime you write, in order to not get duplicated data.

Formatting a text file, how to update the file after I finished parsing it?

How would I open a file, perform some regex on the file, and then save the file?
I know I can open a file, read line by line, but how would I update the actual contents of a file and then save the file?
The following approach would work regardless of file size, and will also not corrupt the original file in anyway if the operation would fail before it is complete:
string inputFile = Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.MyDocuments), "temp.txt");
string outputFile = Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.MyDocuments), "temp2.txt");
using (StreamReader input = File.OpenText(inputFile))
using (Stream output = File.OpenWrite(outputFile))
using (StreamWriter writer = new StreamWriter(output))
{
while (!input.EndOfStream)
{
// read line
string line = input.ReadLine();
// process line in some way
// write the file to temp file
writer.WriteLine(line);
}
}
File.Delete(inputFile); // delete original file
File.Move(outputFile, inputFile); // rename temp file to original file name
string[] lines = File.ReadAllLines(path);
string[] transformedLines = lines.Select(s => Transform(s)).ToArray();
File.WriteAllLines(path, transformedLines);
Here, for example, Transform is
public static string Transform(string s) {
return s.Substring(0, 1) + Char.ToUpper(s[1]) + s.Substring(2);
}
Open the file for read. Read all the contents of the file into memory. Close the file. Open the file for write. Write all contents to the file. Close the file.
Alternatively, if the file is very large:
Open fileA for read. Open a new file (fileB) for write. Process each line of fileA and save to fileB. Close fileA. Close fileB. Delete fileA. Rename fileB to fileA.
Close the file after you finish reading it
Reopen the file for write
Write back the new contents

Categories