MemoryStream'i bir dosyaya / dosyasından kaydetme ve yükleme


281

Bir yapıyı MemoryStreamserileştiriyorum ve serileştirilmiş yapıyı kaydetmek ve yüklemek istiyorum.

Peki, nasıl MemoryStreambir dosyaya kaydetmek ve ayrıca dosyadan geri yüklemek?


Bir dosyaya kaydetmeniz gerekiyorsa neden bir MemoryStream?
Oded

@Oded Ne kullanmalıyım? Bana bir örnek verebilirmisin?
Mehdi Ghiasi

Yanıtlar:


365

Bellek akışının içeriğini başka bir akışa yazmak için MemoryStream.WriteToveya Stream.CopyTo(çerçeve sürümü 4.5.2, 4.5.1, 4.5, 4'te desteklenen) yöntemleri kullanabilirsiniz.

memoryStream.WriteTo(fileStream);

Güncelleme:

fileStream.CopyTo(memoryStream);
memoryStream.CopyTo(fileStream);

13
memoryStream.CopyTo benim için işe yaramadı, WriteTo ise işe yaramadı. Sanırım belki de bunun nedeni hafızamStream.Position 0 değildi
Mark Adamson

10
Evet doğru. Aralarındaki fark, CopyTo'nun her zaman WriteTo gibi başlangıçtan itibaren geçerli konumdan kopyalamasıdır.
AnorZaken

6
Daha [file|memory]Stream.Seek(0, SeekOrigin.Begin);önce eklendiğinde CopyTo, geçerli konum 0 olarak ayarlanır, böylece CopyTotüm akış kopyalanır.
Martin Backasch

264

MemoryStream adının olduğu varsayılarak ms.

Bu kod MemoryStream'i bir dosyaya yazar:

using (FileStream file = new FileStream("file.bin", FileMode.Create, System.IO.FileAccess.Write)) {
   byte[] bytes = new byte[ms.Length];
   ms.Read(bytes, 0, (int)ms.Length);
   file.Write(bytes, 0, bytes.Length);
   ms.Close();
}

ve bu, bir MemoryStream dosyasına bir dosya okur:

using (MemoryStream ms = new MemoryStream())
using (FileStream file = new FileStream("file.bin", FileMode.Open, FileAccess.Read)) {
   byte[] bytes = new byte[file.Length];
   file.Read(bytes, 0, (int)file.Length);
   ms.Write(bytes, 0, (int)file.Length);
}

Net Framework 4 ve üzeri sürümlerde FileStream'i MemoryStream'e kopyalayabilir ve bu kadar basit bir şekilde tersine çevirebilirsiniz:

MemoryStream ms = new MemoryStream();
using (FileStream file = new FileStream("file.bin", FileMode.Open, FileAccess.Read))
    file.CopyTo(ms);

Ve Ters (MemoryStream to FileStream):

using (FileStream file = new FileStream("file.bin", FileMode.Create, System.IO.FileAccess.Write))
    ms.CopyTo(file);

1
FileMode.Open ile okuma örneğinde neden FileMode.Create kullandığınızı sorabilir miyim?
Philter

6
İlk kod bloğunda, bellek akışını diziye manuel olarak kopyalamak yerine, yerleşik ms.ToArray()işlevi kullanabilirsiniz.
Gman

5
Ms.Position = 0 değerini ayarlamak önemlidir, aksi takdirde bayt dizisi (ve dosya) tüm sıfırları içerir.
Gregory Khrapunovich

1
@ Fernando68 yapı using (...){ }tamamen aynı etkiye sahiptir.
Fabricio Araujo

2
Tıpkı diğerlerinin 'FileStream' ve 'ms.CopyTo (file)' komutlarını kullanması için konumu dosyanın sonuna ayarlar ve daha sonra bellek akışını sıfırlamanız gerekir.
Rebecca

64

Akış, bir istisna (dosya G / Ç'de oldukça olası) olsa bile gerçekten atılmalıdır - yan tümceleri kullanmak benim için en sevdiğim yaklaşımdır, bu nedenle MemoryStream'inizi yazmak için şunları kullanabilirsiniz:

using (FileStream file = new FileStream("file.bin", FileMode.Create, FileAccess.Write)) {
    memoryStream.WriteTo(file);
}

Ve tekrar okumak için:

using (FileStream file = new FileStream("file.bin", FileMode.Open, FileAccess.Read)) {
    byte[] bytes = new byte[file.Length];
    file.Read(bytes, 0, (int)file.Length);
    ms.Write(bytes, 0, (int)file.Length);
}

Dosyalar büyükse, okuma işleminin toplam dosya boyutundan iki kat daha fazla bellek kullanacağını belirtmek gerekir . Bunun bir yolu, bayt dizisinden MemoryStream oluşturmaktır - aşağıdaki kod, daha sonra bu akışa yazamayacağınızı varsayar.

MemoryStream ms = new MemoryStream(bytes, writable: false);

Araştırmam (aşağıda), dahili tamponun onu geçtiğinizle aynı bayt dizisi olduğunu gösterir, bu yüzden bellek tasarrufu yapmalıdır.

byte[] testData = new byte[] { 104, 105, 121, 97 };
var ms = new MemoryStream(testData, 0, 4, false, true);
Assert.AreSame(testData, ms.GetBuffer());

41

Kısa sürümleri arayanlar için:

var memoryStream = new MemoryStream(File.ReadAllBytes("1.dat"));

File.WriteAllBytes("1.dat", memoryStream.ToArray()); 

20

Bir dosyaya yazmak için birleşik cevap;

MemoryStream ms = new MemoryStream();    
FileStream file = new FileStream("file.bin", FileMode.Create, FileAccess.Write);
ms.WriteTo(file);
file.Close();
ms.Close();

15

Bir dosyaya kaydet

Car car = new Car();
car.Name = "Some fancy car";
MemoryStream stream = Serializer.SerializeToStream(car);
System.IO.File.WriteAllBytes(fileName, stream.ToArray());

Dosyadan yükle

using (var stream = new MemoryStream(System.IO.File.ReadAllBytes(fileName)))
{
    Car car = (Car)Serializer.DeserializeFromStream(stream);
}

nerede

using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace Serialization
{
    public class Serializer
    {
        public static MemoryStream SerializeToStream(object o)
        {
            MemoryStream stream = new MemoryStream();
            IFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, o);
            return stream;
        }

        public static object DeserializeFromStream(MemoryStream stream)
        {
            IFormatter formatter = new BinaryFormatter();
            stream.Seek(0, SeekOrigin.Begin);
            object o = formatter.Deserialize(stream);
            return o;
        }
    }
}

Başlangıçta bu sınıfın uygulanması burada yayınlanmıştır

ve

[Serializable]
public class Car
{
    public string Name;
}

14

Bir dosyayı yüklemek için bunu daha iyi seviyorum

MemoryStream ms = new MemoryStream();
using (FileStream fs = File.OpenRead(file))
{
    fs.CopyTo(ms);
}

Dosya Microsoft Word'de açılırsa - bu dosyadan bellek akışı oluşturmanın bir yolu var mı? 'Dosya başka bir işlemle açıldı' hatası alıyorum
FrenkyB

@FrenkyB Ben de buna çok giriyorum. Dosya Word veya başka bir uygulamada açıksa, bunu yapamazsınız. Dosyayı Word'de kapatmanız yeterlidir.
Kristopher

@FrenkyB File.Copy yapabilir misiniz? Çalışmak, sonra bu dosyadan bir akışa okumak ve yeni dosyayı silmek ... korkunç bulduk, ama işe yarıyor gibi görünüyor.
ridecar2

3

Görüntü eklemek ve hatta video akışı yapmak için Panel Kontrolü kullanıyorum, ancak görüntüyü SQL Server'da Image veya MySQL olarak largeblob olarak kaydedebilirsiniz . Bu kod benim için çok işe yarıyor. Bunu kontrol et.

İşte görüntüyü kaydedin

MemoryStream ms = new MemoryStream();
Bitmap bmp = new Bitmap(panel1.Width, panel1.Height);
panel1.DrawToBitmap(bmp, panel1.Bounds);
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); // here you can change the Image format
byte[] Pic_arr = new byte[ms.Length];
ms.Position = 0;
ms.Read(Pic_arr, 0, Pic_arr.Length);
ms.Close();

Ve burada yükleyebilirsiniz, ancak bir PictureBox Denetimi kullandım.

MemoryStream ms = new MemoryStream(picarr);
ms.Seek(0, SeekOrigin.Begin);
fotos.pictureBox1.Image = System.Drawing.Image.FromStream(ms);

Umut yardımcı olur.


1
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;

namespace ImageWriterUtil
{
    public class ImageWaterMarkBuilder
    {
        //private ImageWaterMarkBuilder()
        //{
        //}
        Stream imageStream;
        string watermarkText = "©8Bytes.Technology";
        Font font = new System.Drawing.Font("Brush Script MT", 30, FontStyle.Bold, GraphicsUnit.Pixel);
        Brush brush = new SolidBrush(Color.Black);
        Point position;
        public ImageWaterMarkBuilder AddStream(Stream imageStream)
        {
            this.imageStream = imageStream;
            return this;
        }
        public ImageWaterMarkBuilder AddWaterMark(string watermarkText)
        {
            this.watermarkText = watermarkText;
            return this;
        }
        public ImageWaterMarkBuilder AddFont(Font font)
        {
            this.font = font;
            return this;
        }

        public ImageWaterMarkBuilder AddFontColour(Color color)
        {
            this.brush = new SolidBrush(color);
            return this;
        }
        public ImageWaterMarkBuilder AddPosition(Point position)
        {
            this.position = position;
            return this;
        }

        public void CompileAndSave(string filePath)
        {

            //Read the File into a Bitmap.
            using (Bitmap bmp = new Bitmap(this.imageStream, false))
            {
                using (Graphics grp = Graphics.FromImage(bmp))
                {


                    //Determine the size of the Watermark text.
                    SizeF textSize = new SizeF();
                    textSize = grp.MeasureString(watermarkText, font);

                    //Position the text and draw it on the image.
                    if (position == null)
                        position = new Point((bmp.Width - ((int)textSize.Width + 10)), (bmp.Height - ((int)textSize.Height + 10)));
                    grp.DrawString(watermarkText, font, brush, position);

                    using (MemoryStream memoryStream = new MemoryStream())
                    {
                        //Save the Watermarked image to the MemoryStream.
                        bmp.Save(memoryStream, ImageFormat.Png);
                        memoryStream.Position = 0;
                       // string fileName = Path.GetFileNameWithoutExtension(filePath);
                        // outPuthFilePath = Path.Combine(Path.GetDirectoryName(filePath), fileName + "_outputh.png");
                        using (FileStream file = new FileStream(filePath, FileMode.Create, System.IO.FileAccess.Write))
                        {
                            byte[] bytes = new byte[memoryStream.Length];
                            memoryStream.Read(bytes, 0, (int)memoryStream.Length);
                            file.Write(bytes, 0, bytes.Length);
                            memoryStream.Close();
                        }
                    }
                }
            }

        }
    }
}

Kullanım: -

ImageWaterMarkBuilder.AddStream(stream).AddWaterMark("").CompileAndSave(filePath);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.