File manipulation - procedure problems - c#

I've been given a few different sets of procedures for various different things in C# under file manipulation.
I have forgotten basically how to call or use the procedures and so they are pretty much useless to me until I figure out how. Apologies for sounding stupid but I've done as much searching as I can and I can't relate other sources to my problem.
Here's a procedure I've been given:
void readFromTextFile(string path)
{
StreamReader sr = new StreamReader(path);
//Read the first line of text
string line = sr.ReadLine();
//Continue to read until you reach end of file
while (line != null)
{
//write the line to console window
Console.WriteLine(line);
//Read the next line
line = sr.ReadLine();
}
//close the file
sr.Close();
}
Now I understand completely what this and all the other procedures do, yet I forget how to use them in main.
Here's what I currently have in main:
string path = "C:\\Users\\Joe\\Documents\\General\\College\\Computer Science\\Coding\\TextFileWork\\textFile.txt";
string readFile;
readFile = readFromTextFile(path);
Now the problem I'm having is understanding how to use the procedure back into main to return the read file. The string readFile is what I am trying to append the read text into, however I don't know how I should call the function in order to append it. Some basic help should suffice, thanks!
EDIT:
Here's the entire code I currently have (C# Console Application)
namespace TextFileWork_03._03._18
{
class Program
{
static void Main(string[] args)
{
string path = "C:\\Users\\Joe\\Documents\\General\\College\\Computer
Science\\Coding\\TextFileWork\\textFile.txt";
string readFile;
readFromTextFile(readFile);
if (File.Exists(path) == true)
{
//Create a file to write to.
Console.WriteLine(path + " Exists");
}
else
{
Console.WriteLine(path + " File not found");
}
FileInfo fi = new FileInfo(path);
FileStream fs = fi.Create();
fs.Close();
if (File.Exists(path) == true)
{
//Create a file to write to.
Console.WriteLine(path + " Now exists");
}
else
{
Console.WriteLine(path + " File still not found");
}
}
static void readFromTextFile(string path)
{
StreamReader sr = new StreamReader(path);
//Read the first line of text
string line = sr.ReadLine();
//Continue to read until you reach end of file
while (line != null)
{
//write the line to console window
Console.WriteLine(line);
//Read the next line
line = sr.ReadLine();
}
//close the file
sr.Close();
}
}
}

To make your code work you'll need a return value from your method, otherwise you cannot say:
mysomthing = readFromTextFile
So, lets return a string value:
There is one problem: do you want to return a single line or just the whole file?
Here's the whole file version:
static string readFromTextFile(string path)
{
StreamReader sr = new StreamReader(path);
StringBuilder sb = new StringBuilder();
//Read the first line of text
string line = sr.ReadLine();
//Continue to read until you reach end of file
while (line != null)
{
//write the line to console window
Console.WriteLine(line);
//Read the next line
line = sr.ReadLine();
sb.AppendLine(line);
}
//close the file
sr.Close();
return sb.ToString();
}

update this answer is not valid, I'll just keep it for a few minutes for reference.
You should have given more of your code to actually make this a valid question. Nevertheless, I'll try to help you out.
Your procedure (we call it methods in C#, (strongly related to functions)), lives in a class, lets call it Foo, but you can look it up in your code. Just scroll up: its the first blue class you'll see.
public class Foo //this is your class
{
void readFromTextFile(string path)
{
StreamReader sr = new StreamReader(path);
//Read the first line of text
string line = sr.ReadLine();
//Continue to read until you reach end of file
while (line != null)
{
//write the line to console window
Console.WriteLine(line);
//Read the next line
line = sr.ReadLine();
}
//close the file
sr.Close();
}
}
To call it, from your Main method, you'll need an object
void Main()
{
string path = "C:\\Users\\Joe\\Documents\\General\\College\\ComputerScience\\Coding\\TextFileWork\\textFile.txt";
string readFile;
Foo fooObject = new Foo(); //create a new Foo
readFile = fooObject.readFromTextFile(path);
}

Related

Search string by means of StreamReader

I have this code in C # perform a string search from a .txt file, but it shows only one line.
and I need that 3 from the first match.
Example: Search: 1
result
line 1
line 2
line 3
Help me please. regards
.......................................
Text File
Code: 1
Note name: Josh
body Note : tex
Code: 2
Note name: Josh
body note: txt
C# Code
using System;
using System.IO;
class Test
{
public static void Main()
{
enter code here
try
{
string searchString = "some string";
searchString = Console.ReadLine();
// Create an instance of StreamReader to read from a file.
// The using statement also closes the StreamReader.
using (StreamReader sr = new StreamReader("TestFile.txt"))
{
string line;
// Read and display lines from the file until the end of
// the file is reached.
while ((line = sr.ReadLine()) != null)
{
if(line.Contains(searchString))
{
// Do some logic (the search string is found)
// I need to show 3 lines here
// Code:1
// Note name: Josh
// Body Note : tex
// for the moment Console.WriteLine(line);just shows me 1
Console.WriteLine(line);
count++;
}
}
}
}
catch (Exception e)
{
// Let the user know what went wrong.
Console.WriteLine("The file could not be read:");
Console.WriteLine(e.Message);
}
}
}
The reason you are only getting one line is becuase your keep comparing the searchString with each line in the file once a match was found. You could add a flag to bypass the contains like:
bool found = false;
using (StreamReader sr = new StreamReader("TestFile.txt"))
{
string line;
// Read and display lines from the file until the end of
// the file is reached.
while ((line = sr.ReadLine()) != null)
{
// bypass the search once we've found a match
if(found || line.Contains(searchString))
{
// Do some logic (the search string is found)
// I need to show 3 lines here
// Code:1
// Note name: Josh
// Body Note : tex
// for the moment Console.WriteLine(line);just shows me 1
found = true;
Console.WriteLine(line);
count++;
if(count == 3) {
break;
}
}
}
}
Or you could read the stream all the way to its end and then check and post-process:
using (StreamReader sr = new StreamReader("TestFile.txt"))
{
string contents = sr.ReadToEnd();
if (contents.Contains(searchString))
{
// do you magic here
}
}

Streamwriter file is not being created

I'm using the code below to break apart a large text file into smaller files based on the logic you can see here. I'm getting an error on the File.WriteAllText line saying that tempfile doesn't exist. The flow is one header record, followed by multiple report data rows, followed by one end of report line, then it starts over again. Does anyone know why my temp file wouldn't be created here, what am I missing? Thanks.
private static void SplitFile()
{
StreamReader sr = new StreamReader($"{_processDir}{_processFile}");
StreamWriter sw = null;
string fileName = string.Empty;
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
if (line.Split('\t')[0] == "FILEIDENTIFIER")
{
//line is a header record
sw = new StreamWriter("{_processDir}tempfile.txt", false);
sw.WriteLine(line);
}
else if (line.Contains("END OF\tREPORT"))
{
//line is end of report
sw.Close();
File.WriteAllText($"{_processDir}{fileName}.txt", File.ReadAllText($"{_processDir}tempfile.txt"));
}
else
{
//line is a report datarow
fileName = line.Split('\t')[0];
sw.WriteLine(line);
}
}
}
This code is getting you problem :
sw = new StreamWriter("{_processDir}tempfile.txt", false);
Use string interpolation with above code :
sw = new StreamWriter($"{_processDir}tempfile.txt", false);
You can check that where the streamwriter has written the data.

The process cannot access the file because it is being used by another process. (Text File will not close)

I am trying to Write to a text file after this code block checks for the last time the PC was restarted. The code below reads from a text file, the last time the PC was resarted, and from there it determines whether to show a splash-screen. However, After this method runs, i need to write to the text file what the current "System Up-Time" is. But i keep getting an error that says the text file is in use. This has driven me insane. I have made sure all StreamWriters and StreamReaders are closed. I have tried Using Statements. I have tried GC.Collect. I feel like i have tried everything.
Any help would be appreciated.
private void checkLastResart()
{
StreamReader sr = new StreamReader(Path.GetDirectoryName(Application.ExecutablePath) + #"\Settings.txt");
if (sr.ReadLine() == null)
{
sr.Close();
MessageBox.Show("There was an error loading 'System UpTime'. All settings have been restored to default.");
StreamWriter sw = new StreamWriter(Path.GetDirectoryName(Application.ExecutablePath) + #"\Settings.txt", false);
sw.WriteLine("Conversion Complete Checkbox: 0");
sw.WriteLine("Default Tool: 0");
sw.WriteLine("TimeSinceResart: 0");
sw.Flush();
sw.Close();
}
else
{
try
{
StreamReader sr2 = new StreamReader(Path.GetDirectoryName(Application.ExecutablePath) + #"\Settings.txt");
while (!sr2.EndOfStream)
{
string strSetting = sr2.ReadLine();
if (strSetting.Contains("TimeSinceResart:"))
{
double lastTimeRecorded = double.Parse(strSetting.Substring(17));
//If the lastTimeRecorded is greater than timeSinceResart (computer has been resarted) OR 2 hours have passed since LVT was last run
if (lastTimeRecorded > timeSinceRestart || lastTimeRecorded + 7200 < timeSinceRestart)
{
runSplashScreen = true;
}
else
{
runSplashScreen = false;
}
}
}
sr2.Close();
sr2.Dispose();
}
catch (Exception e) { MessageBox.Show("An error has occured loading 'System UpTime'.\r\n\r\n" + e); }
}
}
Below is a sample of writing to the Text file, after the above code has been run. It doesnt matter if i open a StreamWriter, or use File.WriteAllLines, an error is thrown immediately.
StreamWriter sw = new StreamWriter(Path.GetDirectoryName(Application.ExecutablePath) + #"\Settings.txt");
string[] lines = File.ReadAllLines(Path.GetDirectoryName(Application.ExecutablePath) + #"\Settings.txt");
lines[2] = "TimeSinceResart: " + timeSinceRestart;
foreach (string s in lines)
sw.WriteLine(s);
Your writing code should be changed in this way
string file = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),"Settings.txt");
// First read the two lines in memory
string[] lines = File.ReadAllLines(file);
// then use the StreamWriter that locks the file
using(StreamWriter sw = new StreamWriter(file))
{
lines[2] = "TimeSinceResart: " + timeSinceRestart;
foreach (string s in lines)
sw.WriteLine(s);
}
In this way the lock on the StreamWriter doesn't block the reading with FileReadAllLines.
Said that, please note a couple of things. Do not create path strings with string concatenation, use the static methods of the Path class. But most important, when you create a disposable object like a stream be sure to use the using statement to close correctly the file
To complete the answer in response to your comment. Using statement also for the first part of your code
private void checkLastResart()
{
string file = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),"Settings.txt");
using(StreamReader sr = new StreamReader(file))
{
if (sr.ReadLine() == null)
{
sr.Close();
MessageBox.Show(...)
using(StreamWriter sw = new StreamWriter(file, false))
{
sw.WriteLine("Conversion Complete Checkbox: 0");
sw.WriteLine("Default Tool: 0");
sw.WriteLine("TimeSinceResart: 0");
sw.Flush();
}
}
else
{
....
}
} // exit using block closes and disposes the stream
}
Where you create sr2, sr still has settings.txt open.

Using StreamReader to check if a file contains a string

I have a string that is args[0].
Here is my code so far:
static void Main(string[] args)
{
string latestversion = args[0];
// create reader & open file
using (StreamReader sr = new StreamReader("C:\\Work\\list.txt"))
{
while (sr.Peek() >= 0)
{
// code here
}
}
}
I would like to check if my list.txt file contains args[0]. If it does, then I will create another process StreamWriter to write a string 1 or 0 into the file. How do I do this?
Are you expecting the file to be particularly big? If not, the simplest way of doing it would be to just read the whole thing:
using (StreamReader sr = new StreamReader("C:\\Work\\list.txt"))
{
string contents = sr.ReadToEnd();
if (contents.Contains(args[0]))
{
// ...
}
}
Or:
string contents = File.ReadAllText("C:\\Work\\list.txt");
if (contents.Contains(args[0]))
{
// ...
}
Alternatively, you could read it line by line:
foreach (string line in File.ReadLines("C:\\Work\\list.txt"))
{
if (line.Contains(args[0]))
{
// ...
// Break if you don't need to do anything else
}
}
Or even more LINQ-like:
if (File.ReadLines("C:\\Work\\list.txt").Any(line => line.Contains(args[0])))
{
...
}
Note that ReadLines is only available from .NET 4, but you could reasonably easily call TextReader.ReadLine in a loop yourself instead.
You should not add the ';' at the end of the using statement.
Code to work:
string latestversion = args[0];
using (StreamReader sr = new StreamReader("C:\\Work\\list.txt"))
using (StreamWriter sw = new StreamWriter("C:\\Work\\otherFile.txt"))
{
// loop by lines - for big files
string line = sr.ReadLine();
bool flag = false;
while (line != null)
{
if (line.IndexOf(latestversion) > -1)
{
flag = true;
break;
}
line = sr.ReadLine();
}
if (flag)
sw.Write("1");
else
sw.Write("0");
// other solution - for small files
var fileContents = sr.ReadToEnd();
{
if (fileContents.IndexOf(latestversion) > -1)
sw.Write("1");
else
sw.Write("0");
}
}
if ( System.IO.File.ReadAllText("C:\\Work\\list.txt").Contains( args[0] ) )
{
...
}
The accepted answer reads all file in memory which can be consuming.
Here's an alternative inspired by VMAtm answer
using (var sr = new StreamReader("c:\\path\\to\\file", true))
for (string line; (line = sr.ReadLine()) != null;) //read line by line
if (line.Contains("mystring"))
return true;

Edit a specific Line of a Text File in C#

I have two text files, Source.txt and Target.txt. The source will never be modified and contain N lines of text. So, I want to delete a specific line of text in Target.txt, and replace by an specific line of text from Source.txt, I know what number of line I need, actually is the line number 2, both files.
I haven something like this:
string line = string.Empty;
int line_number = 1;
int line_to_edit = 2;
using StreamReader reader = new StreamReader(#"C:\target.xml");
using StreamWriter writer = new StreamWriter(#"C:\target.xml");
while ((line = reader.ReadLine()) != null)
{
if (line_number == line_to_edit)
writer.WriteLine(line);
line_number++;
}
But when I open the Writer, the target file get erased, it writes the lines, but, when opened, the target file only contains the copied lines, the rest get lost.
What can I do?
the easiest way is :
static void lineChanger(string newText, string fileName, int line_to_edit)
{
string[] arrLine = File.ReadAllLines(fileName);
arrLine[line_to_edit - 1] = newText;
File.WriteAllLines(fileName, arrLine);
}
usage :
lineChanger("new content for this line" , "sample.text" , 34);
You can't rewrite a line without rewriting the entire file (unless the lines happen to be the same length). If your files are small then reading the entire target file into memory and then writing it out again might make sense. You can do that like this:
using System;
using System.IO;
class Program
{
static void Main(string[] args)
{
int line_to_edit = 2; // Warning: 1-based indexing!
string sourceFile = "source.txt";
string destinationFile = "target.txt";
// Read the appropriate line from the file.
string lineToWrite = null;
using (StreamReader reader = new StreamReader(sourceFile))
{
for (int i = 1; i <= line_to_edit; ++i)
lineToWrite = reader.ReadLine();
}
if (lineToWrite == null)
throw new InvalidDataException("Line does not exist in " + sourceFile);
// Read the old file.
string[] lines = File.ReadAllLines(destinationFile);
// Write the new file over the old file.
using (StreamWriter writer = new StreamWriter(destinationFile))
{
for (int currentLine = 1; currentLine <= lines.Length; ++currentLine)
{
if (currentLine == line_to_edit)
{
writer.WriteLine(lineToWrite);
}
else
{
writer.WriteLine(lines[currentLine - 1]);
}
}
}
}
}
If your files are large it would be better to create a new file so that you can read streaming from one file while you write to the other. This means that you don't need to have the whole file in memory at once. You can do that like this:
using System;
using System.IO;
class Program
{
static void Main(string[] args)
{
int line_to_edit = 2;
string sourceFile = "source.txt";
string destinationFile = "target.txt";
string tempFile = "target2.txt";
// Read the appropriate line from the file.
string lineToWrite = null;
using (StreamReader reader = new StreamReader(sourceFile))
{
for (int i = 1; i <= line_to_edit; ++i)
lineToWrite = reader.ReadLine();
}
if (lineToWrite == null)
throw new InvalidDataException("Line does not exist in " + sourceFile);
// Read from the target file and write to a new file.
int line_number = 1;
string line = null;
using (StreamReader reader = new StreamReader(destinationFile))
using (StreamWriter writer = new StreamWriter(tempFile))
{
while ((line = reader.ReadLine()) != null)
{
if (line_number == line_to_edit)
{
writer.WriteLine(lineToWrite);
}
else
{
writer.WriteLine(line);
}
line_number++;
}
}
// TODO: Delete the old file and replace it with the new file here.
}
}
You can afterwards move the file once you are sure that the write operation has succeeded (no excecption was thrown and the writer is closed).
Note that in both cases it is a bit confusing that you are using 1-based indexing for your line numbers. It might make more sense in your code to use 0-based indexing. You can have 1-based index in your user interface to your program if you wish, but convert it to a 0-indexed before sending it further.
Also, a disadvantage of directly overwriting the old file with the new file is that if it fails halfway through then you might permanently lose whatever data wasn't written. By writing to a third file first you only delete the original data after you are sure that you have another (corrected) copy of it, so you can recover the data if the computer crashes halfway through.
A final remark: I noticed that your files had an xml extension. You might want to consider if it makes more sense for you to use an XML parser to modify the contents of the files instead of replacing specific lines.
When you create a StreamWriter it always create a file from scratch, you will have to create a third file and copy from target and replace what you need, and then replace the old one.
But as I can see what you need is XML manipulation, you might want to use XmlDocument and modify your file using Xpath.
You need to Open the output file for write access rather than using a new StreamReader, which always overwrites the output file.
StreamWriter stm = null;
fi = new FileInfo(#"C:\target.xml");
if (fi.Exists)
stm = fi.OpenWrite();
Of course, you will still have to seek to the correct line in the output file, which will be hard since you can't read from it, so unless you already KNOW the byte offset to seek to, you probably really want read/write access.
FileStream stm = fi.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
with this stream, you can read until you get to the point where you want to make changes, then write. Keep in mind that you are writing bytes, not lines, so to overwrite a line you will need to write the same number of characters as the line you want to change.
I guess the below should work (instead of the writer part from your example). I'm unfortunately with no build environment so It's from memory but I hope it helps
using (var fs = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite)))
{
var destinationReader = StreamReader(fs);
var writer = StreamWriter(fs);
while ((line = reader.ReadLine()) != null)
{
if (line_number == line_to_edit)
{
writer.WriteLine(lineToWrite);
}
else
{
destinationReader .ReadLine();
}
line_number++;
}
}
The solution works fine. But I need to change single-line text when the same text is in multiple places. For this, need to define a trackText to start finding after that text and finally change oldText with newText.
private int FindLineNumber(string fileName, string trackText, string oldText, string newText)
{
int lineNumber = 0;
string[] textLine = System.IO.File.ReadAllLines(fileName);
for (int i = 0; i< textLine.Length;i++)
{
if (textLine[i].Contains(trackText)) //start finding matching text after.
traced = true;
if (traced)
if (textLine[i].Contains(oldText)) // Match text
{
textLine[i] = newText; // replace text with new one.
traced = false;
System.IO.File.WriteAllLines(fileName, textLine);
lineNumber = i;
break; //go out from loop
}
}
return lineNumber
}

Categories

Resources