8

一時ディレクトリと一時ファイルを作成し、FileStream を使用してファイルを開き、呼び出し元の関数に FileStream を返し、一時ファイルを削除する必要がある C# MVC アプリケーションの関数があります。ただし、「別のプロセスが使用しているため、プロセスはファイルにアクセスできません」と常にエラーになるため、一時ディレクトリとファイルを削除する方法がわかりません。これは私が試したものですが、FileStream はまだ finally ブロックで一時ファイルを使用しています。FileStream を返して一時ファイルを削除するにはどうすればよいですか?

public FileStream DownloadProjectsZipFileStream()
{
    Directory.CreateDirectory(_tempDirectory);
    // temporary file is created here
    _zipFile.Save(_tempDirectory + _tempFileName);

    try
    {
        FileStream stream = new FileStream(_tempDirectory + _tempFileName, FileMode.Open);
        return stream;
    }
    finally
    {
        File.Delete(_tempDirectory + _tempFileName);
        Directory.Delete(_tempDirectory);
    }
}

FileStream が返される関数は次のようになります。

public ActionResult DownloadProjects ()
{
    ProjectDownloader projectDownloader = new ProjectDownloader();

    FileStream stream = projectDownloader.DownloadProjectsZipFileStream();
    return File(stream, "application/zip", "Projects.zip");
}

更新: zip ファイルが 380 MB であることを忘れていました。MemoryStream を使用すると、システムのメモリ不足例外が発生します。

4

5 に答える 5

5

コントラクトを実装し、内部にStreamを含み、ファイルへのパスを維持するラッパー クラスを作成できます。FileStream

標準のメソッドとプロパティはすべて、インスタンスStreamに渡されるだけです。FileStream

このラッパー クラスがDisposed の場合、( Disposewrapped を ing した後FileStream) ファイルを削除します。

于 2013-04-11T06:14:55.473 に答える
1

問題は、ファイルが応答に書き込まれた後にのみファイルを削除でき、ファイルがアクションから返された後にのみ FileStreamResult によって書き込まれることです。

処理する 1 つの方法は、ファイルを削除する FileResult のサブクラスを作成することです。

FilePathResultクラスがファイル名にアクセスできるようにサブクラス化する方が簡単です。

public class FilePathWithDeleteResult : FilePathResult
{
    public FilePathResult(string fileName, string contentType)
        : base(string fileName, string contentType)
    {
    }

    protected override void WriteFile(HttpResponseBase response)
    {
        base.WriteFile(response);
        File.Delete(FileName);
        Directory.Delete(FileName);
    }
}

注:上記はテストしていません。使用する前に、すべてのバグを削除してください。

コントローラーのコードを次のように変更します。

public ActionResult DownloadProjects ()
{
    Directory.CreateDirectory(_tempDirectory);
    // temporary file is created here
    _zipFile.Save(_tempDirectory + _tempFileName);

    return new FilePathWithDeleteResult(_tempDirectory + _tempFileName, "application/zip") { FileDownloadName = "Projects.zip" };
}
于 2013-04-11T05:58:32.100 に答える
1

@hwiechers によって提案された方法を使用しますが、それを機能させる唯一の方法は、ファイルを削除する前に応答ストリームを閉じることです。

これがソースコードです。ストリームを削除する前にフラッシュすることに注意してください。

public class FilePathAutoDeleteResult : FilePathResult
{
    public FilePathAutoDeleteResult(string fileName, string contentType) : base(fileName, contentType)
    {
    }

    protected override void WriteFile(HttpResponseBase response)
    {
        base.WriteFile(response);
        response.Flush();
        File.Delete(FileName);
    }

}

そして、コントローラーがそれを呼び出す方法は次のとおりです。

public ActionResult DownloadFile() {

    var tempFile = Path.GetTempFileName();

    //do your file processing here...
    //For example: generate a pdf file

    return new FilePathAutoDeleteResult(tempFile, "application/pdf")
    {
        FileDownloadName = "Awesome pdf file.pdf"
    };
}
于 2015-04-08T12:16:58.333 に答える