I would like to extract the section of console output that occurs between two specific points in a program and store that into a variable. This would be executed in a loop many times. There is no need for output to be echoed into the regular console (if that makes things more efficient).
i.e.
foreach (Procedure p in procedures) {
BeginCapturingConsoleOutput();
p.Execute();
string procedureOutput = EndCapturingConsoleOutput();
}
The code on this page in MSDN does what I think you are looking for:
http://msdn.microsoft.com/en-us/library/16f09842.aspx
Basically, it sets the output stream to something that you define (in the case of the example, a file), performs some action, and at the end sets it back to the standard output stream.
Related
I have an input text file that comes from a third party and i wrote a c# program to process it and get the results. I have the results and I need to update the same file with the results. The third party updates their DB based on this output file. I need to get the position of the string to update the file.
Ex: The input file looks this way:
Company Name: <some name> ID: <some ID>
----------------------------------------------------
Transaction_ID:0000001233 Name:John Amount:40:00 Output_Code:
-----------------------------------------------------------------------
Transaction_ID:0000001234 Name:Doe Amount:40:00 Output_Code:
------------------------------------------------------------------------
Please note: transaction_ID is unique in each row.
The Output file should be:
Company Name: <some name> ID: <some ID>
----------------------------------------------------
Transaction_ID:0000001233 Name:John Amount:40:00 Output_Code:01
-----------------------------------------------------------------------
Transaction_ID:0000001234 Name:Doe Amount:40:00 Output_Code:02
---------------------------------------------------------------------------
The codes 01 and 02 are the results of the c# program and have to be updated in the response file.
I have the code find out the position of "Transaction_ID:0000001233" and "Output_Code:". I am able to update the first row. But I am not able to get the position of the "Output_Code:" for the second row. How do I identify the string based on the line number?
I cannot rewrite the whole response file as it has other unwanted columns.
The best option here would be to update the existing file.
long positionreturnCode1 = FileOps.Seek(filePath, "Output_Code:");
//gets the position of Output_Code in the first row.
byte[] bytesToInsert = System.Text.Encoding.ASCII.GetBytes("01");
FileOps.InsertBytes(bytesToInsert, newPath, positionreturnCode1);
// the above code inserts "01" in the correct position. ie:first row
long positiontransId2 = FileOps.Seek(filePath, "Transaction_ID:0000001234");
long positionreturnCode2 = FileOps.Seek(filePath, "Output_Code:");
// still gets the first row's value
long pos = positionreturnCode2 - positiontransId2;
byte[] bytesToInsert = System.Text.Encoding.ASCII.GetBytes("02");
FileOps.InsertBytes(bytesToInsert, newPath, pos);
// this inserts in a completely different position.
I know the logic is wrong. But I am trying to get the position of output code value in the second row.
Don't try to "edit" the existing file. There is too much room for error.
Rather, assuming that the file format will not change, parse the file into data, then rewrite the file completely. An example, in pseudo-code below:
public struct Entry
{
public string TransactionID;
public string Name;
public string Amount;
public string Output_Code;
}
Iterate through the file and create a list of Entry instances, one for each file line, and populate the data of each Entry instance with the contents of the line. It looks like you can split the text line using white spaces as a delimiter and then further split each entry using ':' as a delimiter.
Then, for each entry, you set the Output_Code during your processing phase.
foreach(Entry entry in entrylist)
entry.Output_Code = MyProcessingOfTheEntryFunction(entry);
Finally iterate through your list of entries and rewrite the entire file using the data in your Entry list. (Making sure to correctly write the header and any line spacers, etc..)
OpenFile();
WriteFileHeader();
foreach(Entry entry in entrylist)
{
WriteLineSpacer();
WriteEntryData(entry);
}
CloseFile();
To start with, I'll isolate the part that takes a transaction and returns a code, since I don't know what that is, and it's not relevant. (I'd do the same thing even if I did know.)
public class Transaction
{
public Transaction(string transactionId, string name, decimal amount)
{
TransactionId = transactionId;
Name = name;
Amount = amount;
}
public string TransactionId { get; }
public string Name { get; }
public decimal Amount { get; }
}
public interface ITransactionProcessor
{
// returns an output code
string ProcessTransaction(Transaction transaction);
}
Now we can write something that processes a set of strings, which could be lines from a file. That's something to think about. You get the strings from a file, but would this work any different if they didn't come from a file? Probably not. Besides, manipulating the contents of a file is harder. Manipulating strings is easier. So instead of "solving" the harder problem we're just converting it into an easier problem.
For each string it's going to do the following:
Read a transaction, including whatever fields it needs, from the string.
Process the transaction and get an output code.
Add the output code to the end of the string.
Again, I'm leaving out the part that I don't know. For now it's in a private method, but it could be described as a separate interface.
public class StringCollectionTransactionProcessor // Horrible name, sorry.
{
private readonly ITransactionProcessor _transactionProcessor;
public StringCollectionTransactionProcessor(ITransactionProcessor transactionProcessor)
{
_transactionProcessor = transactionProcessor;
}
public IEnumerable<string> ProcessTransactions(IEnumerable<string> inputs)
{
foreach (var input in inputs)
{
var transaction = ParseTransaction(input);
var outputCode = _transactionProcessor.ProcessTransaction(transaction);
var outputLine = $"{input} {outputCode}";
yield return outputLine;
}
}
private Transaction ParseTransaction(string input)
{
// Get the transaction ID and whatever values you need from the string.
}
}
The result is an IEnumerable<string> where each string is the original input, unmodified except for the output code appended that the end. If there were any extra columns in there that weren't related to your processing, that's okay. They're still there.
There are likely other factors to consider, like exception handling, but this is a starting point. It gets simpler if we completely isolate different steps from each other so that we only have to think about one thing at a time.
As you can see, I've still left things out. For example, where do the strings come from? Do they come from a file? Where do the results go? Another file? Now it's much easier to see how to add those details. They seemed like they were the most important, but now we've rearranged this so that they're the least important.
It's easy to write code that reads a file into a collection of strings.
var inputs = file.ReadLines(path);
When you're done and you have a collection of strings, it's easy to write them to a file.
File.WriteAllLines(path, linesToWrite);
We wouldn't add those details into the above classes. If we do, we've restricted those classes to only working with files, which is unnecessary. Instead we just write a new class which reads the lines, gets a collection of strings, passes it to the other class to get processed, gets back a result, and writes it to a file.
This is an iterative process that allows us to write the parts we understand and leave the parts we haven't figured out for later. That keeps us moving forward solving one problem at a time instead of getting stuck trying to solve a few at once.
A side effect is that the code is easier to understand. It lends itself to writing methods with just a few lines. Each is easy to read. It's also much easier to write unit tests.
In response to some comments:
If the output code doesn't go at the end of the line - it's somewhere in the middle, you can still update it:
var line = line.Replace("Output_Code:", "Output_Code:" + outputCode);
That's messy. If the line is delimited, you could split it, find the element that contains Output_Code, and completely replace it. That way you don't get weird results if for some reason there's already an output code.
If the step of processing a transaction includes updating a database record, that's fine. That can all be within ITransactionProcessor.ProcessTransaction.
If you want an even safer system you could break the whole thing down into two steps. First process all of the transactions, including your database updates, but don't update the file at all.
After you're done processing all of the transactions, go back through the file and update it. You could do that by looking up the output code for each transaction in the database. Or, processing transactions could return a Dictionary<string, string> containing the transaction ids and output codes. When you're done with all the processing, go through the file a second time. For each transaction ID, see if there's an output code. If there is, update that line.
The additions here are send in a position based on where your main program has already updated and keep that moving forward ahead the length of what you also added.
I believe if I am reading the code there and in your example correctly this should make you scoot along through the file.
This function is within the utils that you linked in your comment.
public static long Seek(string file, long position, string searchString)
{
//open filestream to perform a seek
using (System.IO.FileStream fs =
System.IO.File.OpenRead(file))
{
fs.Position = position;
return Seek(fs, searchString);
}
}
I started to learn C# a week ago and I'm getting familiarized with the working environment. So far we've learned the usual stuff: variable types, function declarations, how to compile a project, etc.
As the first assignment our teacher gave us a screen capture of how we are supposed to pass arguments to a executable file.
I read thatstring[] args is what is used for "grabbing" from the console and passing on to the rest of the code. However when I try to print like this:
Console.WriteLine(args);
I always get the same result:
How can I pass a parameter to the exe file via the console?
The console is outputting the entire string array object as a string (System.String[]). To see its contents you need to iterate through the array:
foreach (string s in args)
{
Console.WriteLine(s);
}
This will show you the contents of the array. The [0] value will always be the name of the executable, and your parameters will start at position [1].
I am trying to use an ArrayList to store a variable number of strings, and would like to know how to save the ArrayList and its elements so that my windows form can recall their value between program load and exit.
I used to store the information in a text file, but would like to avoid external files if possible.
Thank you for any help you could provide.
You can save the ArrayList (if not ArrayList their are other equivalent classes) using Properties.Settings best part is it allows you the setting variable at Application and user level
A very good example can be found here how to use Settigns http://www.codeproject.com/Articles/17659/How-To-Use-the-Settings-Class-in-C
I've always done using (In Winforms in your case from the sounds of it), the Form_Closing to store to a Properties.Settings variable you'd create beforehand. If it's an ArrayList, you could store it to XML or a comma separated list. Your serizliation/deserialization method will depend on your data.
Have a look at isolated storage.
I used to store the information in a text file, but would like to avoid external files if possible.
Inevitably storing data between runs will require something outside the program's executables.
The registry would work, but the registry is not great for storing anything more than a small amount of information. A database could be used by that adds files.
For text strings a text file – one string per line1 – can be saved and loaded in a single statement. Putting the file into isolated storage or under a dedicated folder in %AppData% limits the chances of a user messing it up.2.
// Load
var theStrings = new ArrayList();
var path = GetSavePath();
if (File.Exists(path)) {
theStrings.AddRange(File.ReadLines(path);
}
// Save:
File.WriteAllLines(GetSavePath(), theStrings.ToArray());
Here using ToArray() as ArrayList doesn't implement IEnumerable<String> (List<String> would be a better choice for a collection and avoid this).
1 This assumes end of line is not valid inside the strings. If this needs to be supported there are a number of options. Some file format to separate the strings by another mechanism, or perhaps the easiest will be to escape characters with a simple transform (eg. \ → \\, newline → \n, and carriage return → \r).
2 You cannot prevent this without significant additional complexity that would use something like a service to load/save as a different user thus allowing the data to be protected by an ACL.
I kind of toil to describe my situation, therefore my post might geht al litle longer.
I want to search for given keys in strings. The strings are lines of a text file, the comparison is to be done as the file is beeing read line by line.
There is a class which has the properties NUMBER and TYPE among others. That are the keys for which is to be searched in the line string.
A trivial solution would be to store the class instances in a list and run through that list for each and every line and see if the line string contains the keys of the current list entry.
The performance of this implementation though would be horrible, since on the average for every line the program will loop through the entire list. This is since every key in the list occures at most one time in the file. So there are a lot of lines which don't contain a key.
I hope you guys get what I'm trying to explain and get the idea.
Example for objects:
O1:
ID - 1
NR - 1587
TYPE - COMPUTER
O2:
ID - 2
NR - 5487
TYPE - TV
text file lines:
bla bla \t 8745 RADIO
fsdakfjd9 9094km d9943
dkjd894 4003p \t 5487 TV
sdj99 43s39 kljljkljfsd
...
On line 3 the program should find the match and save the ID 2 together with the line content.
Thanks for any input ...
Toby
Looking up strings in your file is intensive so ideally, you only want to do this once.
I think it's ideal if you store class references in a Dictionary or a Hashtable.
Then you can do something like
var myDictionary = new Dictionary<string, ObjectType>();
while(string line = reader.ReadLine())
{
// Parse the possible key out of the line
if (myDictionary.ContainsKey(keyFromLine) doSomething(line, myDictionary[keyFromLine]);
}
void doSomething(string line, ObjectType instance)
{
// Unwrap the line and store appropriate values
}
Splitting, counting within strings is by nature resource and time intensive. You need parsing and searching. You have to loop through all the strings and save it, and then search it using Dictionary<key, value>. Try to loop the fewest and the way to accomplish that is by running the program on all the lines and saving it first. Don't scan lines on every search.
Basically I'm still in the starting phase, and I know how to use Console.WriteLine, but I have no idea on how to have it read input from the user.
For example, I'd want a user to be able to type in a pair of numbers, then return the result.
My goal is a program that receives input , then combines them and returns the average.
This is all in Visual C# Express 2008
string input = Console.ReadLine();
that will return you a string of the user's input. Check out MSDN for documentation on the Console class. Also look at the Convert class.
int num = Convert.ToInt32(input);
Good luck new coder.
First create a variable to store the user input, like this:
int variablenameofyourchoice = 0;
Then take input like this and store it in your variable name:
variablenameofyourchoice = int.parse(Console.ReadLine())
Then do whatever you want with that variable. If you want two numbers do this twice.
This is a very general topic with a lot of answers, but Console.ReadLine is one counterpart of Console.WriteLine. It reads a line of text from standard in.
Have a look at Console.ReadLine() or Console.Read() in the MSDN Documentation