どうやら私は悪いコーディング習慣に身を投じました。これが私が書いてきたコードの例です:
_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
句がStreamReader
でClose()
およびDispose()
を明示的に呼び出したため、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
に変更したことに注意してください。そうでない場合はcouldは、古いファイルを処理するアプリである可能性があります。これはうまくいきますか?
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
}
この場合の破棄の順序は、ネストされたブロックと同じです(つまり、この場合、StreamReaderはFileStreamの前に破棄されます)。
FileInfo.Open()
と_File.Move(
_)の代わりにFileInfo.MoveTo()
とFile.Open()
を使用してみます。 FileInfo.OpenText()
を使用することもできます。しかし、これらは単なる提案です。
他の何かがsomefile.txtをロックしている可能性はありますか?
ローカル(ファイル)のコマンドラインからの簡単なチェック
net files
他に何かロックがある場合、いくつかの手がかりを与えるかもしれません。
または、 FileMon のようなものを取得してさらに詳細を取得し、アプリが適切にリリースされていることを確認することもできます。
これはコーディングの問題ではないようなので、syadminの帽子をかぶって、いくつかの提案をします。
編集:サーバーマシンからの行為でそれをキャッチできる場合、Sysinternalのハンドルが開いているものを教えてくれます。