Ответ 1
Ваша проблема: Excel открывает файл как чтение/запись. File.ReadAllLines()
не может получить доступ к файлу, когда он открыт для записи в другом приложении. Если вы открыли csv в Excel только для чтения, вы не столкнетесь с этим исключением.
Это связано с тем, что реализация в .Net не открывает внутренний поток с соответствующими разрешениями для доступа к файлу, когда другое приложение имеет права на запись.
Итак, исправление здесь простое, напишите свой собственный метод ReadAllLines()
, который устанавливает соответствующие разрешения при запуске базового Stream
.
Здесь идея, которая сильно зависит от того, что ReadAllLines()
делает сама по себе:
public string[] WriteSafeReadAllLines(String path)
{
using (var csv = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var sr = new StreamReader(csv))
{
List<string> file = new List<string>();
while (!sr.EndOfStream)
{
file.Add(sr.ReadLine());
}
return file.ToArray();
}
}
Единственное различие между этим и тем, что ReadAllLines
делает, - это разрешение FileShare
установлено на FileShare.ReadWrite
, что позволяет открывать файл, даже если он открыт с разрешениями на чтение/запись в другом приложении.
Теперь вам нужно понять проблемы, которые могут возникнуть из-за этого, поскольку могут быть сложности, поскольку у другого приложения есть права на запись в файл.
- Вы будете читать последнюю сохраненную версию файла, поэтому, если у вас есть несохраненные изменения в Excel, этот метод не будет их читать.
- Если вы сохраните файл в Excel, пока этот метод находится в середине чтения, вы, вероятно, получите исключение в зависимости от обстоятельств. Это связано с тем, что файл полностью заблокирован во время сохранения, поэтому, если вы попытаетесь прочитать файл, когда он заблокирован, он выкинет
System.IO.IOException
. - И если вы сохраните файл и избегаете исключения (крайне маловероятно, но возможно заданное конкретное время), вы будете читать вновь сохраненный файл, а не оригинал.
Чтобы понять, почему вы не можете прочитать файл, когда он открыт для записи другим приложением, вы должны посмотреть на фактическую реализацию в .NET. (Это реализация в .Net 4.5, поэтому она может немного отличаться, если вы смотрите на разностную версию .Net).
Вот что выглядит File.ReadAllLines()
:
public static string[] ReadAllLines(string path)
{
if (path == null)
throw new ArgumentNullException("path");
if (path.Length == 0)
throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"));
else
return File.InternalReadAllLines(path, Encoding.UTF8);
}
private static string[] InternalReadAllLines(string path, Encoding encoding)
{
List<string> list = new List<string>();
using (StreamReader streamReader = new StreamReader(path, encoding))
{
string str;
while ((str = streamReader.ReadLine()) != null)
list.Add(str);
}
return list.ToArray();
}
И заглянуть в то, что StreamReader
делает внутренне:
internal StreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool checkHost)
{
if (path == null || encoding == null)
throw new ArgumentNullException(path == null ? "path" : "encoding");
if (path.Length == 0)
throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"));
if (bufferSize <= 0)
throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
this.Init((Stream) new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan, Path.GetFileName(path), false, false, checkHost), encoding, detectEncodingFromByteOrderMarks, bufferSize, false);
}
Итак, мы пришли к тому, что исключение - это бросок, когда он снабжен контуром, StreamReader
создает FileStream
, у которого параметр FileShare
установлен на Read
. Это означает, что он не может совместно использовать файл с другим приложением с доступом для чтения/записи к файлу. Чтобы отменить это поведение, вам нужно указать Stream
с другим параметром FileShare
, что я и сделал в вышеприведенном решении.