Any non-novice C# developer definitely knows the File.ReadAllBytes method, which is a widely used way to read a file contents in memory. The method is basically a wrapper that opens a FileStream instance to read the file contents, then reads the stream content and returns its byte array.
As explained here, the underlying FileStream gets opened using the FileShare.Read flag in combination with FileAccess.Read, meaning that concurrent calls to the File.ReadAllBytes method on the same file would never throw a "used by another process" System.IO.IOException... unless another process already has it open with a write lock: in such scenarios, the FileShare.Read will fail with the following error message:
System.IO.IOException: the process can't access the file because it is being used by another process
System.IO.IOException: Il processo non può accedere al file perché è in uso da un altro processo.
If you see the above exception, you basically have two options:
- Wait and retry until the writing lock expires. Such approach is greatly covered in this StackOverflow thread.
- Manually open a FileStream using the FileShare.ReadWrite flag instead of the built-in FileShare.Read used by the File.ReadAllBytes helper method (as detailed in this other StackOverflow thread).
The former workaround might create issues with thread-locking, hence I don't suggest it unless you really need to enforce the write lock. The latter, other than being rather simple to implement, is also easily understandable: the FileShare.Read flag, as the name implies, allows only concurrent reads: conversely, FileShare.ReadWrite allows concurrent reads and writes, meaning that you'll be able to read and/or write the file regardless of what other threads are actually doing. Which is precisely what we need to get rid of the System.IO.IOException error above.
Here's a viable helper method that extends File.ReadAllBytes with such convenient feature:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/// <summary> /// File.ReadAllBytes alternative to avoid read and/or write locking /// </summary> private byte[] ReadAllBytes2(string filePath, FileAccess = FileAccess.Read, FileShare shareMode = FileShare.ReadWrite) { using (var fs = new FileStream(filePath, FileMode.Open, fileAccess, shareMode)) { using (var ms = new MemoryStream()) { fs.CopyTo(ms); return ms.ToArray(); } } } |
That's about it: I hope that this brief analysis will be useful to many who are struggling over this nasty issue.