既存のプロセスが保持しているファイルの削除に失敗する
-
20-08-2019 - |
質問
C#で書いているコードに問題があります。
MailMessageおよびSMTPコンポーネントを使用してドキュメントを送信しています。送信するファイルをc:\ tempなどの一時ディレクトリにコピーし、ドキュメントをループしてメールに添付します。
メールは正常に送信されますが、一時ディレクトリからファイルを削除しようとすると、次のエラーが表示されます:
このプロセスは別のプロセスによって使用されているため、ファイルにアクセスできません
なぜこれが起こっているのか理解できません。以下はドキュメントを処理するコードです
public void sendDocument(String email, string barcode, int requestid)
{
string tempDir = @"c:\temp";
//first we get the document information from the database.
Database db = new Database(dbServer, dbName, dbUser, dbPwd);
List<Document> documents = db.getDocumentByID(barcode);
int count = 0;
foreach (Document doc in documents)
{
string tempPath = tempDir + "\\" + doc.getBarcode() + ".pdf";
string sourcePath = doc.getMachineName() + "\\" + doc.getFilePath() + "\\" + doc.getFileName();
//we now copy the file from the source location to the new target location
try
{
//this copies the file to the folder
File.Copy(sourcePath, tempPath, false);
}
catch (IOException ioe)
{
count++;
//the file has failed to copy so we add a number to the file to make it unique and try
//to copy it again.
tempPath = tempDir + "\\" + doc.getBarcode() + "-" + count + ".pdf";
File.Copy(sourcePath, tempPath, false);
}
//we now need to update the filename in the to match the new location
doc.setFileName(doc.getBarcode() + ".pdf");
}
//we now email the document to the user.
this.sendEmail(documents, email, null);
updateSentDocuments(documents, email);
//now we update the request table/
db.updateRequestTable(requestid);
//now we clean up the documents from the temp folder.
foreach (Document doc in documents)
{
string path = @"c:\temp\" + doc.getFileName();
File.Delete(path);
}
}
削除を失敗させているのはsmtpオブジェクトだと思うので、this.sendEmail()メソッドはsendDocumentメソッドに戻る前にメールを送信すると思っていました。
これはsendEmailメソッドです:
public void sendEmail(List<Document> documents, String email, string division)
{
String SMTPServer = null;
String SMTPUser = null;
String SMTPPwd = null;
String sender = "";
String emailMessage = "";
//first we get all the app setting used to send the email to the users
Database db = new Database(dbServer, dbName, dbUser, dbPwd);
SMTPServer = db.getAppSetting("smtp_server");
SMTPUser = db.getAppSetting("smtp_user");
SMTPPwd = db.getAppSetting("smtp_password");
sender = db.getAppSetting("sender");
emailMessage = db.getAppSetting("bulkmail_message");
DateTime date = DateTime.Now;
MailMessage emailMsg = new MailMessage();
emailMsg.To.Add(email);
if (division == null)
{
emailMsg.Subject = "Document(s) Request - " + date.ToString("dd-MM-yyyy");
}
else
{
emailMsg.Subject = division + " Document Request - " + date.ToString("dd-MM-yyyy");
}
emailMsg.From = new MailAddress(sender);
emailMsg.Body = emailMessage;
bool hasAttachements = false;
foreach (Document doc in documents)
{
String filepath = @"c:\temp\" + doc.getFileName();
Attachment data = new Attachment(filepath);
emailMsg.Attachments.Add(data);
hasAttachements = true;
}
SmtpClient smtp = new SmtpClient(SMTPServer);
//we try and send the email and throw an exception if it all goes tits.
try
{
if (hasAttachements)
{
smtp.Send(emailMsg);
}
}
catch (Exception ex)
{
throw new Exception("EmailFailure");
}
}
削除したいファイルを占有するプロセスでこの問題を回避する方法。
アプリケーションが終了したら、ファイルを削除できます。
解決
メールメッセージは破棄されていません。送信後に破棄してみてください。
try
{
if (hasAttachements)
{
smtp.Send(emailMsg);
}
}
catch ...
finally
{
emailMsg.Dispose();
}
他のヒント
最初のステップは、問題のファイルを保持しているプロセスを把握することです。 SysInternalsツールキットを取得し、handle.exeコマンドを使用して、ファイルに保持しているプロセスを特定します。
ファイルを開いているプロセスがわからない場合、この問題を修正する方法はありません。
Sysinternalsリンク: http://technet.microsoft.com/en- us / sysinternals / default.aspx
ここで私が発見したトリックを紹介します。これは他の人にも役立つでしょうか? メッセージに添付ファイルを追加する前に、使用中のラッパーで添付ファイルを作成します。これにより、ファイルが正しく破棄され、ファイルを正常に削除できます。送信もこのループ内にある必要があるかどうかはわかりません。 (私がテストしたとき、最初はメールが届かなかったが、30分後に洪水に襲われたので、ネットワークが少し落ち着いた時期にテストを辞めることにした。)
using (Attachment attachment = new Attachment(filename))
{
message.Attachments.Add(attachment);
client.SendAsync(message, string.Empty);
}
File.Delete(filename);
とにかくうまくいく:)
幸運を祈ります
JB