2

I am trying to do something like this:

I have 3 files which contain strings

  1. read 3 files and create a 4th file which contains the 3 files content
  2. the reading is suppose to be done with threads which will run in parallel
  3. 4th thread to write for the 4th file

my questions are , how do you do the reading properly ? , how do you make sure that the 4th thread will only run after all files have been red, how do you get the strings content to the 4th thread ?

after reading the files , the 4th files should contain the strings in lexicography order, delate any spaces , signs and repeated words (no need to give implementation of that, just recommend where to code this and how to do it properly)

I used tasks , I want to know how to use threads as well for that in this code the strings array is to demonstrate the files

how do i properly read the file in the "run" function of each thread?

using System;
using System.Threading.Tasks;
using System.IO;
using System.Text;

class Program {


  static void Main() {

     StringBuilder stringToRead = new StringBuilder();
     StringReader reader;

    Task [] tasks = new Task[3];
    string [] filz = {"aaa" , "bbb" , "ccc"};
    string [] red = new string[filz.Length];

    foreach(string str in filz){
    stringToRead.AppendLine(str);
    }    


     for (int i = 0; i < tasks.Length ; i++)
      {
          tasks[i] = Task.Run(() =>  Console.WriteLine(i)); // it prints 3 , 3 , 3
      }
       try {
         Task.WaitAll(tasks);
      }
      catch (AggregateException ae) {
         Console.WriteLine("One or more exceptions occurred: ");
         foreach (var ex in ae.Flatten().InnerExceptions)
            Console.WriteLine("   {0}", ex.Message);
      }   

      Console.WriteLine("Status of completed tasks:");
      foreach (var t in tasks)
         Console.WriteLine("   Task #{0}: {1}", t.Id, t.Status);

        //now:  
        //4th thread that will writh the 3 previous files that have been red and writh it to a new file


  }
}
Tal
  • 29
  • 3
  • how do you need to reassemble the new file? Does the new file have to be built in a specific order? If each file you read have different size, they will take a different amount of time to be read... Do you need to reassemble the files in order or can the order be different than the reading order? If the order has to stay the same, you'll want to wait on all the reading threads, and then kick off the process to write. – blaze_125 Sep 06 '19 at 15:51
  • I don't think the order of the files matters, just the make sure every file have been red before I write the new file – Tal Sep 06 '19 at 16:40

1 Answers1

2

Here is a solution using await in a .NET framework application:

This is a button click event, notice the "async" in the function definition:

private async void button1_Click(object sender, EventArgs e)
{

    List<Task> tasks = new List<Task>();

        string path = "C:\\Temp\\testfileread\\";
        Task<string> file1Read = ReadTextAsync(Path.Combine(path, "test1.txt"));
        Task<string> file2Read = ReadTextAsync(Path.Combine(path, "test2.txt"));
        Task<string> file3Read = ReadTextAsync(Path.Combine(path, "test3.txt"));


        await Task.WhenAll(file1Read, file2Read, file3Read);

        string text1 = await file1Read;
        string text2 = await file2Read;
        string text3 = await file3Read;


        await WriteTextAsync(Path.Combine(path, "result.txt"), text1 + text2 + text3);

}

Here are the read and write functions:

   private async Task<string> ReadTextAsync(string filePath)
    {
        using (var reader = File.OpenText(filePath))
        {
            var fileText = await reader.ReadToEndAsync();
            return fileText;
        }
    }

    private async Task WriteTextAsync(string filePath, string value)
    {
        using (StreamWriter writer = File.CreateText(filePath))
        {
            await writer.WriteAsync(value);
        }
    }




The code is nearly the same but here is a solution done in a .NET Core console Application:

static void Main(string[] args)
{
    try
    {
        var result = combineFiles().Result;
    }
    catch (ArgumentException aex)
    {
        Console.WriteLine($"Caught ArgumentException: {aex.Message}");
    }
}

static async Task<bool> combineFiles()
{

    List<Task> tasks = new List<Task>();

    string path = "C:\\Temp\\testfileread\\";
    Task<string> file1Read = ReadTextAsync(Path.Combine(path, "test1.txt"));
    Task<string> file2Read = ReadTextAsync(Path.Combine(path, "test2.txt"));
    Task<string> file3Read = ReadTextAsync(Path.Combine(path, "test3.txt"));


    await Task.WhenAll(file1Read, file2Read, file3Read);

    string text1 = await file1Read;
    string text2 = await file2Read;
    string text3 = await file3Read;


    await WriteTextAsync(Path.Combine(path, "result.txt"), text1 + text2 + text3);

    Console.WriteLine("Finished combining files");
    Console.ReadLine();
    return true;
}


private static async Task<string> ReadTextAsync(string filePath)
{
    using (var reader = File.OpenText(filePath))
    {
        var fileText = await reader.ReadToEndAsync();
        return fileText;
    }
}

private static async Task WriteTextAsync(string filePath, string value)
{
    using (StreamWriter writer = File.CreateText(filePath))
    {
        await writer.WriteAsync(value);
    }
}

dont forget the needed using lines:

using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
CarCar
  • 680
  • 4
  • 13
  • 2
    FYI, with path aggregation it's preferable to use Path.Combine instead of `path + 'file.txt'` – Zulukas Sep 06 '19 at 17:19
  • 1
    Thank you for suggesting async/await! There's no reason to use threads in a situation like this when concurrent async task code will do just fine. Since the OP is using a console app, it's worth mentioning that recent versions of C#/.NET allow for an `async` Main method. – StriplingWarrior Sep 06 '19 at 17:52
  • @StriplingWarrior what do you mean no reason to use Threads? , he is using Task isn't this considered thread? , also I mentioned to be able to do so with threads aswell , you have any idea how to do so efficient ? , also Zulukas , can you give a code example for path combine in this case ? – Tal Sep 06 '19 at 19:16
  • @CarCar can you explain why first function called button click and why it has unused object sender? how do you combine this solution with main for example ? – Tal Sep 06 '19 at 19:25
  • modified answer to use Path.Combine – CarCar Sep 06 '19 at 19:25
  • Yes Tasks are considered multi threading but using the await/async model makes dealing with multiple threads very easy and newbie friendly. especially when trying to move data between threads – CarCar Sep 06 '19 at 19:27
  • And if I have only .net Core ? how should I deal with this ? @CarCar – Tal Sep 06 '19 at 19:29
  • code is same to do this in a .net core application. i added another example to my answer to do it in a console application though. – CarCar Sep 06 '19 at 19:44
  • @CarCar thanks for that , but .NET core 2.2 even supports Tasks? , also , after reading the file I need to : be able to show the strings in lexicography order, delate any spaces , signs and repeated words . Print the most common word and its number of appearance , GIVE AN OPTION to sort the words between top down or down to top SORT([-a,-d]) , and lastly give and option to choose the sign that will be between each word (split new line/ comma/ space ([-s,-c,-n]) do you have any idea how to implement it correctly ? I escpieclly the options part – Tal Sep 07 '19 at 10:01
  • @Tal: It is perfectly possible to use multiple `Task`s on a single thread. Calling `Task.Run` forces a thread to be allocated to the given task, but if you avoid calls like that then threading strategy is defined by the current Task Scheduler, which typically depends on the type of application you're in (WPF, ASP.NET, Console, etc.). The `async`/`await` code in the first example probably would run on one (UI) thread, which starts three I/O operations, frees up the UI thread, and then continues on the UI thread after those I/O operations complete. – StriplingWarrior Sep 08 '19 at 22:51
  • correct, the i/o operations do not run on the UI thread, they run asynchronously – CarCar Sep 09 '19 at 14:54
  • @CarCar `List tasks = new List();` whats that for ? never used – Tal Sep 11 '19 at 09:14
  • its a strongly typed collection of objects. In this case a List of Task – CarCar Sep 11 '19 at 14:32