I'm learning C and C#, this question is for C#. I have this while loop and it is resulting in a infinite loop. I have used this before and it always worked great. But now it just loops forever and never exits. I'm doing this while loop to count the number of lines in the file.
Here is the code:
using (TextReader obj2 = new StreamReader(combined))
{
int count = 1;
while (obj2.Peek() != -1)
{
count++;
}
obj2.Close();
TextWriter obj = File.AppendText(combined);
Console.Write("How many lines do you want to add to the file?:");
int numberOfLines = 0;
int lineNumer = count + 1;
numberOfLines = Convert.ToInt32(Console.ReadLine());
for (int i = 0; i < numberOfLines; i++)
{
Console.Write("Enter a line of text:");
string line = Console.ReadLine();
obj.WriteLine(lineNumer + ". " + line);
}
}
Peek() doesn't advanced the reader. You need to make a call to obj2.Read() inside your loop, or it will never terminate as you've seen.
From the linked MSDN reference:
Reads the next character without changing the state of the reader or
the character source. Returns the next available character without
actually reading it from the reader.
See also Read() on MSDN.
These two methods work hand-in-hand quite often so that you can check if the stream has ended without affecting it. You're on the right track!
Related
I am playing with C#. I try to write program that frames the quote entered by a user in a square of chars. So, the problem is... a user needs to indicate the number of lines before entering a quote. I want to remove this moment, so the user just enters lines of their phrase (each line is a new element in the string array, so I guess a program should kinda declare it by itself?..). I hope I explained clear what I meant x).
I've attached the program code below. I know that it is not perfect (for example, when entering the number of lines, I use the conversion to an integer, and if a user enters a letter, then this may confuse my electronic friend, this is a temporary solution, since I do not want to ask this x) The program itself must count these lines! x)) Though, I don't understand why the symbols on the left side are displayed incorrectly when the program displays output, but I think this also does not matter yet).
//Greet a user, asking for the number of lines.
Console.WriteLine("Greetings! I can put any phrase into beautiful #-square."
+ "\n" + "Wanna try? How many lines in the quote: ");
int numberOfLines = Convert.ToInt32(Console.ReadLine());
//Asking for each line.
string[] lines = new string[numberOfLines];
for (int i = 0; i < numberOfLines; i++)
{
Console.WriteLine("Enter the line: ");
lines[i] = Console.ReadLine();
}
//Looking for the biggest line
int length = 0;
for (int i = 0; i < numberOfLines; i++)
{
if (length < lines[i].Length) length = lines[i].Length;
}
//Starting framing
char doggy = '#';
char space = ' ';
length += 4;
string frame = new String(doggy, length);
Console.WriteLine(frame);
for (int i = 0; i < numberOfLines; i++)
{
string result = new string(space, length - 3 - lines[i].Length);
Console.WriteLine(doggy + space + lines[i] + result + doggy);
}
Console.WriteLine(frame);
Console.ReadLine();
}
}
}
There is performance gap and functionality between "Generic Lists" and arrays, you can read more about cons and pros of this two objects in the internet,
for example you can use list as Dai mentioned in comment like this
List<string> list = new List<string>();
list.Add("one");
list.Add("two");
list.Add("three");
or you can use arraylist
ArrayList arraylist = new ArrayList();
arraylist.Add();
or even you can change the size of array any times but it erase data in it
int[] arr = new int[100];
there is a function called ToArray() you can use it to change generic list to array
Your problem of the left side output is, that you add two values of char. This is not what you expect to be. You must convert the char to a string to append it to other strings:
Console.WriteLine(doggy.ToString() + space.ToString() + lines[i] + result + doggy.ToString());
I have searched numerous web pages but I can't seem to find anywhere which shows how to stop a blank line appearing at the end of a file when using StreamWriter.
The code I've written below is the only way I can get this to work for me.. and although this works perfectly fine for the utility I am creating, I would like to know if there is a better/more efficient way to do this?
int count = 0;
int lineCount = newFile.Count;
using (System.IO.StreamWriter extract = new System.IO.StreamWriter(outputFile, true))
{
foreach (var line in newFile)
{
count++;
if (count != lineCount)
{
extract.Write(line + Environment.NewLine);
}
else
{
extract.Write(line);
}
}
}
Any thoughts people?
Since you are accessing the Count property, it means that your newFile source implements the IList interface. This means that you can access it by its index.
Use for loop instead of foreach:
for (int i = 0; i < newFile.Count - 1; i++)
{
extract.WriteLine(newFile[i]);
}
extract.Write(newFile[newFile.Count - 1]);
Check this...
var values = Enumerable.Range(1,10);
var output = string.Format(string.Join(",{0}", values), Environment.NewLine);
File.WriteAllText(path, output);
I've been researching and i found stuff with the Parallel.For but I can't figure out how to code it without some kind of error.
One error i keep getting, is that there are multiple processors trying to access the same file.
I currently have code that is sequential but that takes a long time. My text file is 10GB.
This is my sequential part, I failed in all attempts to parallel it
for (int i = 0; i <= 10; i++)
{
Console.WriteLine("Parsing List: " + i);
min_chunk += chunk;
max_chunk += chunk;
if (max_chunk >= lines)
{
max_chunk = lines - 1;
}
if (i == 0)
{
min_chunk = 0;
max_chunk = chunk;
}
int diff = (int)(max_chunk - min_chunk);
splitFile("sort.txt", min_chunk, max_chunk, i);
}
public static void splitFile(string path, int min, int max, int threadnum)
{
string outFileName = String.Concat("list", threadnum, ".txt");
System.IO.StreamWriter outfile = new System.IO.StreamWriter(outFileName);
for (int currline = min; currline < max; currline++)
{
string line = File.ReadLines("sort.txt").Skip(currline).Take(1).First();
outfile.WriteLine(line);
}
outfile.Close();
}
}
Here are few links already answered related to your question
splitting large files
parallel c#
splitting text file into multiple
You don't need multiple threads to speed this up.
What you really want is to read the file once, and split it as you go. I don't really understand what you're doing with the min_chunk and max_chunk, but what I would suggest is that you define a chunk size, say it's 10,000 lines. You can then do this:
int maxLines = 10,000;
int numLines = 0;
int fileNumber = 0;
var writer = File.CreateText("list" + fileNumber + ".txt");
foreach (var line in File.ReadLines("sort.txt"))
{
writer.WriteLine(line);
++numLines;
if (numLines == maxLines)
{
writer.Close();
numLines = 0;
++fileNumber;
writer = File.Create("list" + fileNumber + ".txt");
}
}
writer.Close();
Using multiple threads to split a single text file usually won't speed things up. For two reasons.
First, if you have 10 threads going, the first thread reads the first N lines and outputs them. At the same time, the second thread is reading the same file, skipping the first N lines and writing the next N lines. With 10 threads, you have the file open 10 times and all but one of the threads is spending most of its time reading and skipping over stuff that it doesn't care about.
Also, the disk can only do one thing at a time. When multiple threads are trying to write to a single disk, it's slower than having a single thread do it. When a single thread is writing to the disk, it can just write ... and write ... and write. When multiple threads are trying to write, one writes, then the disk has to reposition the read/write head before it can write for the next thread, etc. Those repositionings (called head seeks) take a lot of time--on the order of 5 to 10 milliseconds, which is an eternity in CPU time. What happens is that your threads spend most of their time waiting for other threads to write.
Update
If for some reason you're dead set on doing this with multiple threads, you need to fix this loop in your splitFile method:
for (int currline = min; currline < max; currline++)
{
string line = File.ReadLines("sort.txt").Skip(currline).Take(1).First();
outfile.WriteLine(line);
}
Given that loop and min = 100 and max = 200, then it's going to read the file 100 times. The first time it will skip 100 lines and output 1. Then it'll close the file and the next time through the loop it'll skip 101 lines and output 1. That's going to take quite a long time.
You can change that to:
foreach (var line in File.ReadLines("sort.txt").Skip(min).Take(max-min))
{
outfile.WriteLine(line);
}
In fact if you really wanted to get fancy, you could write:
File.WriteAllLines(outFileName, File.ReadLines("sort.txt").Skip(min).Take(max-min));
But you still have the problem of multiple threads trying to access the same input file. If File.ReadLines is opening the file in exclusive mode, then you have two choices:
use a lock to prevent multiple files from trying to access the file concurrently
open the file with permissive sharing
An example of option 2:
using (var fs = new FileStream("sort.txt", FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (var reader = new StreamReader(fs))
{
int i = 0;
while (!reader.EndOfStream && i < max)
{
string line = reader.ReadLine();
if (i > min)
outfile.WriteLine(line);
++i;
}
}
}
That will do what you're asking. It's not a very smart way to do things, though, because you have 10 threads all reading the same file concurrently, and most of them are spending their time skipping over lines. You're doing a whole lot of unnecessary work. The simple single-threaded version that I presented first is going to outperform this, especially if the output files are all on the same drive.
I need method of lines, so that when you have method call Rows (4), a method prints four blank lines.
This is my code but it wont work, tell me what is wrong?
namespace something
{
class Program
{
static void Main(string[] args)
{
Console.Write("give number: ");
int lines = int.Parse(Console.ReadLine());
line(lines);
Console.WriteLine("lines end");
Console.ReadKey();
}
private static void line(int lines)
{
for (int i = 1; i <= lines; i++);
Console.WriteLine(" ");
}
}
}
Remove ; at the end:
for (int i = 1; i <= lines; i++);
^
In this case your Console.WriteLine(" "); called only once after loop finished. Loop doing nothing.
for (int i = 1; i <= lines; i++); // note the semicolon!
Console.WriteLine(" ");
Should be
for (int i = 1; i <= lines; i++)
Console.WriteLine(" ");
The colon is an empty instruction in its own right. So basically your program was executing an empty instruction n times (or 'lines' times, actually), and it would write an empty line only ever once afterwards.
Interestingly, the Possible mistaken empty statement compiler warning is only displayed when you enwrap the Console.WriteLine line in brackets.
Whatever causes that, it seems like a one more good reason to use brackets, even for code blocks consisting of single instructions.
Thus I would recommend:
for (int i = 1; i <= lines; i++)
{
Console.WriteLine(" ");
}
The semi-colon on the end of your for clause is the issue. Your loop isn't doing anything.
for (int i = 1; i <= lines; i++)
Console.WriteLine(" ");
First of all you should check for the user input to be a number, and display an error message if it isn't. The code, like that, will throw an exception if the user inputs something that can't be parsed to an int.
Then there's the semicolon at the end of the for. That's a compiler error which I think you already noticed when trying to run it.
Apart from that, what exactly is not working? Your "line" method is printi a white space for every number, and not a line. If you want to print a blank line, use Environment.NewLine
very confused by this, when I read in a file using the code below when it gets to the end it prints out FFFFFF, could anyone explain this to me the text file only has numbers and letters in it? Any help would be most greatful!
String fileDirectory = "C:\\t.txt";
StreamReader reader = new StreamReader(fileDirectory);
int hexIn;
for (int i = 0; (hexIn = reader.Read()) != -1; i++)
{
String s;
s = hexIn.ToString("X2");
int x = 0;
while (x < 1)
{
hexIn = reader.Read();
s = hexIn.ToString("X2");
x++;
}
hexIn = reader.Read();
s = hexIn.ToString("X2");
MessageBox.Show(s);
}
You've got three Read calls per loop iteration, which means that any one of them could return -1 to indicate the end of the file. I suspect that's then being converted to FFFFFFFF, hence your output. Why do you have more than one Read call? And why aren't you reading a block at a time?
The FFFFFF may also indicate an empty value. If you Hex editted Nintendo DS Roms you would see a whole bunch of FFFFFFFF at the end which is put there because the game is too small for the cartridge so in actual fact that file may have empty values at the end.