-2

I keep getting the following exception:

System.IO.IOException HResult=0x80070020 Message=The process cannot access the file 'C:\DIPV3\result.csv' because it is being used by another process.

Is there a better way to attempt this solution using a combination of Streams or Linq? The code below writes the file partially but then throws an the exception stated above.

string sourceDir = @"C:\DIPV3";
string output = @"C:\DIPV3\result.csv";

//Thread.Sleep(5000);
File.WriteAllLines(output, 
    Directory.EnumerateFiles(sourceDir, @"*.csv").SelectMany(file => File.ReadLines(file)));
Rufus L
  • 36,127
  • 5
  • 30
  • 43
theDoron1
  • 53
  • 5
  • 3
    Put your output file in a different folder than the one you are enumerating – Steve Apr 30 '19 at 17:11
  • 2
    By the way, the error message you got is famously somewhat incorrect/incomplete. Not only would you get this error message if another process/program has a handle open to the file in question, but you also get the same error message if _your own_ program has already an open handle to the file and tries to open the file again. In your case, your program is opening the output file to write to it (File.WriteAllLines), but then the Directory.EnumerateFiles/SelectMany/File.ReadLines combo will try to open this output file again, while File.WriteAllLines holds an open handle to this file. Kaboom! –  Apr 30 '19 at 17:18
  • It is worth mentioning that .SelectMany(...) evaluates lazily, i.e., the expression/code in the lambda expression `file => File.ReadLines(file)` is only executed when the enumerable returned by .SelectMany(...) is actually being enumerated/iterated. So, who is enumerating this .SelectMany(...) enumerable here? It is the code of the File.WriteAllLines method. Thus File.ReadLines is being executed while File.WriteAllLines is executing, leading to the problem of File.ReadLines trying to open a file that File.WriteAllLines already has and keeps open during its execution... –  Apr 30 '19 at 17:23

1 Answers1

2

The problem is that you're trying to write to the same file that you're reading from (your output file is in the sourceDir and matches the "*.csv" filter.

A few possible solutions are:

1 . Select all files except the output file for reading:

File.WriteAllLines(output, Directory.EnumerateFiles(sourceDir, @"*.csv")
    .Where(path => !path.Equals(output, StringComparison.OrdinalIgnoreCase))
    .SelectMany(File.ReadLines));

2 . Put your output file in a different folder:

string output = @"C:\DIPV3\restuls\result.csv";

3 . Read all the contents first, then write the result:

IEnumerable<string> contents = Directory.EnumerateFiles(sourceDir, @"*.csv")
    .SelectMany(File.ReadLines).ToList();

File.WriteAllLines(output, contents);
Rufus L
  • 36,127
  • 5
  • 30
  • 43
  • 1
    Your 3rd suggested solution does not read the content first and then write the result. It is rather functionally equivalent to the code in the question. I guess you just forgot to add an `.ToArray()` or `.ToList()`. I hope you don't mind me adding it there ;-) –  Apr 30 '19 at 18:30
  • Rufus, how would you iterate through an IEnumerable and split each line of the csv by the separator? In my instance the columns in the csv files are separated by tabs. – theDoron1 Apr 30 '19 at 18:37
  • 1
    @Denz, if you have a(nother) programming question, then write up a new question. Do not (mis)use the comment section underneath an answer (or underneath a question, for that matter) to ask a new question. –  Apr 30 '19 at 19:01
  • @Denz If you did ask that as a new question, it would likely get duplicated to: https://stackoverflow.com/questions/5282999/reading-csv-file-and-storing-values-into-an-array (you would replace the `';'` with `'\t'` to split on the tab character). Just search for ["how to read a csv file c#"](https://www.google.com/search?q=how+to+read+a+csv+file+c%23) in your favorite search engine... – Rufus L Apr 30 '19 at 22:27