Закроет ли предложение использования этого потока?
-
22-08-2019 - |
Вопрос
Я, очевидно, работал в плохой привычке кодирования. Вот пример кода, который я писал:
using(StreamReader sr = new StreamReader(File.Open("somefile.txt", FileMode.Open)))
{
//read file
}
File.Move("somefile.txt", "somefile.bak"); //can't move, get exception that I the file is open
Я думал об этом, потому что using
пункт явно называется Close()
а также Dispose()
на StreamReader
что FileStream
Также будет закрыт.
Единственный способ решить проблему, которая была у меня, - это изменить вышеупомянутый блок на это:
using(FileStream fs = File.Open("somefile.txt", FileMode.Open))
{
using(StreamReader sr = new StreamReader(fs))
{
//read file
}
}
File.Move("somefile.txt", "somefile.bak"); // can move file with no errors
Должен закрыть StreamReader
Удаление в первом блоке также закрывает базовый FileStream
? Или я ошибался?
Редактировать
Я решил опубликовать фактический оскорбительный блок кода, чтобы увидеть, сможем ли мы добраться до нижней части этого. Мне просто любопытно.
Я думал, что у меня есть проблема в using
Пункт, поэтому я все расширил, и он все еще не может копировать каждый раз. Я создаю файл в этом вызове метода, поэтому я не думаю, что что -то еще имеет ручку, открывающуюся в файле. Я также подтвердил, что строки вернулись из Path.Combine
звонки верны.
private static void GenerateFiles(List<Credit> credits)
{
Account i;
string creditFile = Path.Combine(Settings.CreditLocalPath, DateTime.Now.ToString("MMddyy-hhmmss") + ".credits");
StreamWriter creditsFile = new StreamWriter(File.Open(creditFile, FileMode.Create));
creditsFile.WriteLine("code\inc");
foreach (Credit c in credits)
{
if (DataAccessLayer.AccountExists(i))
{
string tpsAuth = DataAccessLayer.GetAuthCode(i.Pin);
creditsFile.WriteLine(String.Format("{0}{1}\t{2:0.00}", i.AuthCode, i.Pin, c.CreditAmount));
}
else
{
c.Error = true;
c.ErrorMessage = "NO ACCOUNT";
}
DataAccessLayer.AddCredit(c);
}
creditsFile.Close();
creditsFile.Dispose();
string dest = Path.Combine(Settings.CreditArchivePath, Path.GetFileName(creditFile));
File.Move(creditFile,dest);
//File.Delete(errorFile);
}
Решение
Да, StreamReader.Dispose
Закрывает базовый поток (для всех общественных способов его создания). Тем не менее, есть более приятная альтернатива:
using (TextReader reader = File.OpenText("file.txt"))
{
}
Это имеет дополнительное преимущество, что он открывает базовый поток с подсказкой для Windows, к которым вы будете получать к нему доступ.
Вот тестовое приложение, которое показывает первую версию, работающую для меня. Я не пытаюсь сказать, что это доказательство чего -либо конкретного, но я бы хотел знать, насколько хорошо это работает для вас.
using System;
using System.IO;
class Program
{
public static void Main(string[] args)
{
for (int i=0; i < 1000; i++)
{
using(StreamReader sr = new StreamReader
(File.Open("somefile.txt", FileMode.Open)))
{
Console.WriteLine(sr.ReadLine());
}
File.Move("somefile.txt", "somefile.bak");
File.Move("somefile.bak", "somefile.txt");
}
}
}
Если это работает, это говорит о том, что это связано с тем, что вы делаете во время чтения ...
А теперь вот сокращенная версия вашего отредактированного кода вопроса, которая снова работает для меня, даже на сетевой общей обмене. Обратите внимание, что я изменил FileMode.Create
к FileMode.CreateNew
- как иное там мог По -прежнему было приложением с ручкой на старом файле, потенциально. Это работает для вас?
using System;
using System.IO;
public class Test
{
static void Main()
{
StreamWriter creditsFile = new StreamWriter(File.Open("test.txt",
FileMode.CreateNew));
creditsFile.WriteLine("code\\inc");
creditsFile.Close();
creditsFile.Dispose();
File.Move("test.txt", "test2.txt");
}
}
Другие советы
Примечание - ваши блоки не должны быть вложены в свои собственные блоки - они могут быть последовательными, как в:
using(FileStream fs = File.Open("somefile.txt", FileMode.Open))
using(StreamReader sr = new StreamReader(fs))
{
//read file
}
Порядок распоряжения в этом случае остается таким же, как вложенные блоки (т. Е. Поток читатель все равно будет распоряжаться перед FileStream в этом случае).
Я бы попытался использовать FileInfo.Open()
а также FileInfo.MoveTo()
вместо File.Open()
а также File.Move(
) Вы также можете попробовать использовать FileInfo.OpenText()
. Анкет Но это просто предложения.
Есть ли вероятность, что что -то еще имеет замок на somefile.txt?
Простая проверка из локальной (в файл) строки CMD
net files
Вполне может дать вам некоторые подсказки, если что -нибудь еще имеет замок.
В качестве альтернативы вы можете получить что -то вроде Filemon Чтобы получить еще больше деталей и проверить, что ваше приложение выпускается правильно.
Поскольку это не является проблемой кодирования, я собираюсь надеть шляпу Syadmin и предложить несколько предложений.
- Сканер вируса на клиенте или сервере, который сканирует файл при его создании.
- Окна оппортунистическая блокировка Имеет привычку прикручивать вещи в сетевых акциях. Я помню, что это в основном проблема с несколькими клиентами чтения/записи с плоскими базами данных, но кэширование Конечно, может объяснить вашу проблему.
- Окна Файл открыть кэш. Анкет Я не уверен, что это все еще проблема в Win2K или нет, но Filemon скажет вам.
РЕДАКТИРОВАТЬ: Если вы можете поймать его в ACT с серверной машины, то ручка Sysinternal сообщит вам, что его открыт.