首页 文章

如何将流保存到C#中的文件?

提问于
浏览
615

我有一个 StreamReader 对象,我用流初始化,现在我想将此流保存到磁盘(流可能是 .gif.jpg.pdf ) .

现有守则:

StreamReader sr = new StreamReader(myOtherObject.InputStream);
  • 我需要将其保存到磁盘(我有文件名) .

  • 将来我可能希望将其存储到SQL Server .

我也有编码类型,如果我将它存储到SQL Server,我将需要,对吗?

9 回答

  • 61

    为什么不使用FileStream对象?

    public void SaveStreamToFile(string fileFullPath, Stream stream)
    {
        if (stream.Length == 0) return;
    
        // Create a FileStream object to write a stream to a file
        using (FileStream fileStream = System.IO.File.Create(fileFullPath, (int)stream.Length))
        {
            // Fill the bytes[] array with the stream data
            byte[] bytesInStream = new byte[stream.Length];
            stream.Read(bytesInStream, 0, (int)bytesInStream.Length);
    
            // Use FileStream object to write to the specified file
            fileStream.Write(bytesInStream, 0, bytesInStream.Length);
         }
    }
    
  • 7

    我没有得到 CopyTo 的所有答案,也许使用该应用程序的系统可能尚未升级到.NET 4.0 . 我知道有些人想强迫人们升级,但兼容性也很好 .

    另一件事,我没有首先使用流从另一个流复制 . 为什么不这样做:

    byte[] bytes = myOtherObject.InputStream.ToArray();
    

    获得字节后,您可以轻松地将它们写入文件:

    public static void WriteFile(string fileName, byte[] bytes)
    {
        string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        if (!path.EndsWith(@"\")) path += @"\";
    
        if (File.Exists(Path.Combine(path, fileName)))
            File.Delete(Path.Combine(path, fileName));
    
        using (FileStream fs = new FileStream(Path.Combine(path, fileName), FileMode.CreateNew, FileAccess.Write))
        {
            fs.Write(bytes, 0, (int)bytes.Length);
            //fs.Close();
        }
    }
    

    这段代码可以正常运行,因为我已经用 .jpg 文件对它进行了测试,但我承认我只使用了小文件(小于1 MB) . 一个流,流之间没有复制,不需要编码,只需写入字节!如果你已经拥有一个可以直接用 .ToArray() 转换为 bytes 的流,则无需使用 StreamReader 过度复杂化!

    我只能通过这种方式看到的潜在缺点是,如果有一个大文件,将其作为流并使用 .CopyTo() 或等效允许 FileStream 流式传输而不是使用字节数组并逐个读取字节 . 结果这样做可能会慢一些 . 但它不应该阻塞,因为 FileStream.Write() 方法处理写入字节,并且's only doing it one byte at a time, so it won' t阻塞内存,除了 you will have to have enough memory to hold the stream as a byte[] object . 在我使用它的情况下,得到 OracleBlob ,我不得不去 byte[] ,它足够小,而且,无论如何,我没有可用的流,所以我只是将我的字节发送到我的函数,上面 .

    使用流的另一个选择是将它与Jon Skeet的另一篇文章中的 CopyStream 函数一起使用 - 这只是使用 FileStream 来获取输入流并直接从中创建文件 . 它没有像他那样使用 File.Create (最初对我来说似乎有问题,但后来发现它可能只是一个VS bug ......) .

    /// <summary>
    /// Copies the contents of input to output. Doesn't close either stream.
    /// </summary>
    public static void CopyStream(Stream input, Stream output)
    {
        byte[] buffer = new byte[8 * 1024];
        int len;
        while ( (len = input.Read(buffer, 0, buffer.Length)) > 0)
        {
            output.Write(buffer, 0, len);
        }    
    }
    
    public static void WriteFile(string fileName, Stream inputStream)
    {
        string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        if (!path.EndsWith(@"\")) path += @"\";
    
        if (File.Exists(Path.Combine(path, fileName)))
            File.Delete(Path.Combine(path, fileName));
    
        using (FileStream fs = new FileStream(Path.Combine(path, fileName), FileMode.CreateNew, FileAccess.Write)
        {
            CopyStream(inputStream, fs);
        }
    
        inputStream.Close();
        inputStream.Flush();
    }
    
  • 797

    另一种选择是将流转换为 byte[] 并使用 File.WriteAllBytes . 这应该做:

    using (var stream = new MemoryStream())
    {
        input.CopyTo(stream);
        File.WriteAllBytes(file, stream.ToArray());
    }
    

    将它包装在扩展方法中可以更好地命名:

    public void WriteTo(this Stream input, string file)
    {
        //your fav write method:
    
        using (var stream = File.Create(file))
        {
            input.CopyTo(stream);
        }
    
        //or
    
        using (var stream = new MemoryStream())
        {
            input.CopyTo(stream);
            File.WriteAllBytes(file, stream.ToArray());
        }
    
        //whatever that fits.
    }
    
  • 482
    public void CopyStream(Stream stream, string destPath)
    {
      using (var fileStream = new FileStream(destPath, FileMode.Create, FileAccess.Write))
      {
        stream.CopyTo(fileStream);
      }
    }
    
  • 5

    正如Tilendor在Jon Skeet的回答中强调的那样,自.NET 4以来,流有一个 CopyTo 方法 .

    var fileStream = File.Create("C:\\Path\\To\\File");
    myOtherObject.InputStream.Seek(0, SeekOrigin.Begin);
    myOtherObject.InputStream.CopyTo(fileStream);
    fileStream.Close();
    

    或者使用 using 语法:

    using (var fileStream = File.Create("C:\\Path\\To\\File"))
    {
        myOtherObject.InputStream.Seek(0, SeekOrigin.Begin);
        myOtherObject.InputStream.CopyTo(fileStream);
    }
    
  • 21
    private void SaveFileStream(String path, Stream stream)
    {
        var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write);
        stream.CopyTo(fileStream);
        fileStream.Dispose();
    }
    
  • 3
    //If you don't have .Net 4.0  :)
    
    public void SaveStreamToFile(Stream stream, string filename)
    {  
       using(Stream destination = File.Create(filename))
          Write(stream, destination);
    }
    
    //Typically I implement this Write method as a Stream extension method. 
    //The framework handles buffering.
    
    public void Write(Stream from, Stream to)
    {
       for(int a = from.ReadByte(); a != -1; a = from.ReadByte())
          to.WriteByte( (byte) a );
    }
    
    /*
    Note, StreamReader is an IEnumerable<Char> while Stream is an IEnumbable<byte>.
    The distinction is significant such as in multiple byte character encodings 
    like Unicode used in .Net where Char is one or more bytes (byte[n]). Also, the
    resulting translation from IEnumerable<byte> to IEnumerable<Char> can loose bytes
    or insert them (for example, "\n" vs. "\r\n") depending on the StreamReader instance
    CurrentEncoding.
    */
    
  • 4

    您不能将 StreamReader 用于二进制文件(如gifs或jpgs) . StreamReader 用于文本数据 . 如果将它用于任意二进制数据,几乎肯定会丢失数据 . (如果你使用Encoding.GetEncoding(28591)你可能会没事,但重点是什么?)

    为什么你需要使用 StreamReader ?为什么不将二进制数据保存为二进制数据并将其作为二进制数据写回磁盘(或SQL)?

    编辑:因为这似乎是人们想要看到的东西......如果你只是想将一个流复制到另一个(例如复制到文件),请使用以下内容:

    /// <summary>
    /// Copies the contents of input to output. Doesn't close either stream.
    /// </summary>
    public static void CopyStream(Stream input, Stream output)
    {
        byte[] buffer = new byte[8 * 1024];
        int len;
        while ( (len = input.Read(buffer, 0, buffer.Length)) > 0)
        {
            output.Write(buffer, 0, len);
        }    
    }
    

    要使用它将流转储到文件,例如:

    using (Stream file = File.Create(filename))
    {
        CopyStream(input, file);
    }
    

    请注意,Stream.CopyTo是在.NET 4中引入的,基本上用于相同的目的 .

  • 8
    public void testdownload(stream input)
    {
        byte[] buffer = new byte[16345];
        using (FileStream fs = new FileStream(this.FullLocalFilePath,
                            FileMode.Create, FileAccess.Write, FileShare.None))
        {
            int read;
            while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
            {
                 fs.Write(buffer, 0, read);
            }
        }
    }
    

相关问题