临时文件流处理(Handling with temporary file stream)

2019-07-20 21:37发布

说我要来定义,创建使用Path.GetTempFileName()方法的临时文件的TempFileStream类。 临时文件必须被删除时不再需要TempFileStream的对象,例如关闭或释放:

class TempFileStream: FileStream
{
  string m_TempFileName = Path.GetTempFileName();
  public TempFileStream(FileMode fileMode): base(m_TempFileName,fileMode) {}

  /// ...

 public ovverride Dispose(bool disposing)
 {
   /// ???
 }

}   

我应该如何简单,安全地实现这一点?

Answer 1:

试试这个来代替:

public class TempFileStream : FileStream
{
    public TempFileStream()
        : base(Path.GetTempFileName(), FileMode.Create, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.DeleteOnClose) { }
    public TempFileStream(FileAccess access)
        : base(Path.GetTempFileName(), FileMode.Create, access, FileShare.Read, 4096, FileOptions.DeleteOnClose) { }
    public TempFileStream(FileAccess access, FileShare share)
        : base(Path.GetTempFileName(), FileMode.Create, access, share, 4096, FileOptions.DeleteOnClose) { }
    public TempFileStream(FileAccess access, FileShare share, int bufferSize)
        : base(Path.GetTempFileName(), FileMode.Create, access, share, bufferSize, FileOptions.DeleteOnClose) { }
}

该FileOptions.DeleteOnClose选项将确保OS会自动删除临时文件,当您关闭了该文件。 无需特殊的Dispose方法,因为这一切都为你的照顾。



Answer 2:

这是一个有趣的想法,但也有一些关于这个设计,困扰我。 原谅我,如果你已经解决了这个在您的设计。 但是,如果你的设计是围绕只是一个简单的包装FileStream ,有一个微妙的,但我认为,显著的问题。

如果你删除文件时流被关闭,这意味着该文件在实际使用中的数据的唯一途径是,如果FileAccessReadWrite 。 正确? 换句话说,你将使用的代码看起来像这样的文件:

using (TempFileStream t as new TempFileStream())
{
   WriteDataToTempFile(t);
   t.Seek(0, SeekOrigin.Begin);
   ReadDataFromTempFile(t);
}

我看到的问题是, ReadDataFromTempFile期待文件进行读取访问被打开,而不是读/写访问。 这开辟了一些错误,我认为会很努力找上了门。 考虑这样的代码:

using (TempFileStream t as new TempFileStream())
{
   MyClass o = new MyClass(o);
   o.TempStream = t;
   o.ProduceOutput();
   t.Seek(0, SeekOrigin.Begin);
   o.ProcessOutput();
}

......与此相比,当:

MyClass o = new MyClass();
string n = Path.GetTempFileName();
using (FileStream s = new FileStream(n, FileMode.Create, FileAccess.Write))
{
   o.TempStream = t;
   o.ProduceOutput();
}
using (FileStream s = new FileStream(n, FileMode.Open, FileAccess.Read))
{
   o.TempStream = t;
   o.ProcessOutput();
}
File.Delete(n);

当然,第一种方法是比所述第二短。 但是,如果第二个方法会抛出异常ProcessOutput调用写入方法TempStream 。 (或设置其set访问引发其事件处理程序分派给写入方法的调用事件的性质TempStream ,该如何这个问题最终可能会发生的事情。)第一个将只产生无缘无故意想不到的效果。

你可以解决这个问题,我认为,通过让TempFileStream类开放底层FileStream使用FileAccess.Write 。 然后实现Rewind封闭这种方法FileStream ,并创建一个使用一个新的FileAccess.Read 。 如果你这样做,试图,而它的开放读访问(反之亦然)写入到文件的任何方法至少会抛出异常。



Answer 3:

我知道这是一个较旧的线程,但这里是一个替代的解决方案。 我开始实行TempFileStream,但我想更多的并发。 我用例涉及出口[潜在的宏块]数据库结果通过MVC CSV文件。 我想立即开始下载到客户端的数据都可以从数据库中查询,而不是等待一个潜在的大临时文件被写入之前,我开始下载。

在这个解决方案,我启动一个单独的线程,其填补了AnonymousPipeStream查询。 然后主线程可以从管作为其可用的另一端发出声音的数据。 它使用.NET 4个的任务。

希望别人认为这很有用。

-抢

控制方法:

public FileResult ResultExport ( ReportOptions options )
{
    ResultExport rpt = new ResultExport( options );
    HttpContext.Response.BufferOutput = false;
    return File( rpt.Export(), "text/csv", "results.csv" );
}

模型:

public ResultExport
{
    private AnonymousPipeServerStream WriteStream = null;

    public Stream Export()
    {
        //
        // We'll fire off the database query in a background
        // thread.  It will write data to one end of the pipe.  We'll return the reader
        // end of that pipe to our caller.
        //
        WriteStream = new AnonymousPipeServerStream( PipeDirection.Out );
        AnonymousPipeClientStream reader = new AnonymousPipeClientStream( PipeDirection.In, WriteStream.ClientSafePipeHandle );

        //
        // Call Execute() in a background thread.
        //
        Task.Factory.StartNew( () => Execute() );

        //
        // While Execute() is filling the pipe with data,
        // return the reader end of the pipe to our caller.
        //
        return reader;
    }

    private void Execute ()
    {
        //
        // WriteStream should only by populated by Export()
        //
        if( WriteStream != null )
        {
            using ( StreamWriter sw = new StreamWriter( WriteStream, Encoding.UTF8, 4096 ) )
            {
                //
                // Shove data into the StreamWriter as we get it from the database
                //
                foreach ( string line in ExportCore() )
                {
                    // Each line is a comma-delimited set of values
                    sw.WriteLine( line );
                }
            }
        }
    }
}


Answer 4:

base.Dispose(disposing); // disposes the base stream so the file is no longer used
if (disposing)
    File.Delete(m_TempFileName); // deletes the file

如果你需要,你应添加适当的异常处理的File.Delete。



Answer 5:

基本上按照TempFileStream逻辑,你总是用独特的名字刚创建的文件(即Path.GetTempFileName做什么),而你总是在使用之后将其删除。 因此,有没有需要提供构造函数接受的FileMode,你总是在相同的方式使用它。



文章来源: Handling with temporary file stream