Search code examples
c#filestreamstreamreaderstreamwriter

How to make my StreamWriter faster?


I have C# code like this :

string strFilePath = @
"E:\input.txt";
string strFilePath2 = @
"E:\output.txt";
const int BufferSize = 65536; // 64 Kilobytes
FileStream fs = new FileStream(strFilePath2, FileMode.OpenOrCreate);
using(StreamWriter sw = new StreamWriter(fs)) {
    for (int ww = 0; ww < File.ReadLines(strFilePath).Count(); ww++) {

        string tx2 = GetLine(strFilePath, ww).Replace("||", "| |");

        var first = String.Join("", tx2.TakeWhile(c => Char.IsDigit(c) || c == '|' || c == '-'));
        var third = String.Join("", tx2.Reverse().TakeWhile(c => Char.IsDigit(c) || c == '|' || c == '-').Reverse());
        var second = tx2.Replace(first, "").Replace(third, "");

        string awal = first.ToString();
        string dua = third.ToString();
        string gabung = (awal + dua).Replace("||", "|") + Environment.NewLine;

        string[] pdua = dua.Split('|');

        int totalkanan = int.Parse(pdua[1]) + int.Parse(pdua[2]) + int.Parse(pdua[3]) + int.Parse(pdua[4]) + int.Parse(pdua[5]) + int.Parse(pdua[6]) + int.Parse(pdua[7]) + int.Parse(pdua[8]) + int.Parse(pdua[9]) + int.Parse(pdua[10]) + int.Parse(pdua[11]) + int.Parse(pdua[12]) + int.Parse(pdua[13]) + int.Parse(pdua[14]) + int.Parse(pdua[15]) + int.Parse(pdua[16]) + int.Parse(pdua[17]) + int.Parse(pdua[18]) + int.Parse(pdua[19]);
        if (totalkanan > 0) {

            sw.Write(gabung);

        }
    }       
}

Get Line Method :

string GetLine(string fileName, int line)
{
 using (var sr = new StreamReader(fileName))
    {
      sr.ReadLine();
      for (int i = 1; i < line; i++)
      sr.ReadLine();
      return sr.ReadLine();
    }
}

Input Example :

937|41|0|0|0|0|484|0|0|0|0|0|0|0|20||1|First lesson is when you'll be tested on your knowledge of the Elements of Darkness. Your task is to go get 20 Darkness elements from the Bale professors at the Zone of Darkness Elements.|2582|4342|1|0|0|0|0|470|0|0|0|0|0|0|0|0|0|0|0|
937|42|4335|1|0|0|470|0|0|0|0|0|0|0|2|Pass the test.|1||0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
937|43|0|0|0|0|483|0|0|0|0|0|0|0|42||1|There are no more tests to take.|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
937|44|7928|20|4348|1|481|0|0|0|0|0|0|0|42||1|Congratulations on your completion of all the lessons! Come back in a little while to receive your diploma.|2583|7928|-20|4348|-1|0|0|483|0|0|0|0|0|0|0|0|0|0|0|
937|45|7927|20|4347|1|479|0|0|0|0|0|0|0|42||1|Very nice~! Next, you'll be tested on the Elements of light.|2584|7927|-20|4347|-1|0|0|481|0|0|0|0|0|0|0|0|0|0|0|
937|46|7926|20|4346|1|477|0|0|0|0|0|0|0|42||1|Very nice~! Next, you'll be tested on the Elements of light.|2585|7926|-20|4346|-1|0|0|479|0|0|0|0|0|0|0|0|0|0|0|

Output :

937|41|0|0|0|0|484|0|0|0|0|0|0|0|20|2582|4342|1|0|0|0|0|470|0|0|0|0|0|0|0|0|0|0|0|
937|42|4335|1|0|0|470|0|0|0|0|0|0|0|2|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
937|43|0|0|0|0|483|0|0|0|0|0|0|0|42|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
937|44|7928|20|4348|1|481|0|0|0|0|0|0|0|42|2583|7928|-20|4348|-1|0|0|483|0|0|0|0|0|0|0|0|0|0|0|
937|45|7927|20|4347|1|479|0|0|0|0|0|0|0|42|2584|7927|-20|4347|-1|0|0|481|0|0|0|0|0|0|0|0|0|0|0|
937|46|7926|20|4346|1|477|0|0|0|0|0|0|0|42|2585|7926|-20|4346|-1|0|0|479|0|0|0|0|0|0|0|0|0|0|0|

This program is working , but the problem is when input file has 17k ++ line, the writing progress is very slow , but when input file just 4k+ it just about 10 second , the logic is why 4k take 10 sec , while 17k more than 5 minutes ? any suggestion to solving this ? Thank you in advance !


Solution

  • Your GetLine() method has to read the whole file (upto the line in question), each time to get 1 line.

    Because of this, you will see exponentially poor performance.

    Why not just read each line as you go?

    string strFilePath = @"E:\input.txt";
    string strFilePath2 = @"E:\output.txt";
    const int BufferSize = 65536; // 64 Kilobytes
    
    using (StreamWriter sw = new StreamWriter(fs))
    {
        foreach (var line in File.ReadLines(strFilePath))
        {
            string tx2 = line.Replace("||", "| |");
            var first = String.Join("", tx2.TakeWhile(c => Char.IsDigit(c) || c == '|' || c == '-'));
            var third = String.Join("", tx2.Reverse().TakeWhile(c => Char.IsDigit(c) || c == '|' || c == '-').Reverse());
            var second = tx2.Replace(first, "").Replace(third, "");
    
            string awal = first.ToString();
            string dua = third.ToString();
            string gabung = (awal + dua).Replace("||", "|") + Environment.NewLine;
    
            string[] pdua = dua.Split('|');
    
            int totalkanan = int.Parse(pdua[1]) + int.Parse(pdua[2]) + int.Parse(pdua[3]) + int.Parse(pdua[4]) + int.Parse(pdua[5]) + int.Parse(pdua[6]) + int.Parse(pdua[7]) + int.Parse(pdua[8]) + int.Parse(pdua[9]) + int.Parse(pdua[10]) + int.Parse(pdua[11]) + int.Parse(pdua[12]) + int.Parse(pdua[13]) + int.Parse(pdua[14]) + int.Parse(pdua[15]) + int.Parse(pdua[16]) + int.Parse(pdua[17]) + int.Parse(pdua[18]) + int.Parse(pdua[19]);
            if (totalkanan > 0)
            {
                sw.Write(gabung);
            }
        }
    }