Simpan dan muat MemoryStream ke / dari file

281

Saya membuat serial struktur ke dalam MemoryStreamdan saya ingin menyimpan dan memuat struktur serial.

Jadi, Bagaimana cara Menyimpan MemoryStreamfile ke dalam dan juga memuat kembali dari file?

Mahdi Ghiasi
sumber
Jika Anda perlu menyimpan ke file, mengapa Anda menggunakan MemoryStream?
Oded
@Oded Apa yang harus saya gunakan? Bisakah Anda memberi saya contoh?
Mahdi Ghiasi

Jawaban:

365

Anda dapat menggunakan MemoryStream.WriteToatau Stream.CopyTo(didukung dalam kerangka versi 4.5.2, 4.5.1, 4.5, 4) metode untuk menulis konten aliran memori ke aliran lain.

memoryStream.WriteTo(fileStream);

Memperbarui:

fileStream.CopyTo(memoryStream);
memoryStream.CopyTo(fileStream);
adatapost
sumber
13
memoryStream.CopyTo tampaknya tidak berfungsi untuk saya, sementara WriteTo melakukannya. Saya pikir mungkin itu karena memoryStream.Posisi saya bukan 0
Mark Adamson
10
Ya itu benar. Perbedaan di antara mereka adalah bahwa CopyTo menyalin dari posisi apa pun saat ini bukannya selalu dari awal seperti yang dilakukan WriteTo.
AnorZaken
6
Menambahkan [file|memory]Stream.Seek(0, SeekOrigin.Begin);sebelum CopyToakan mengatur posisi saat ini ke 0, sehingga CopyToakan menyalin aliran lengkap.
Martin Backasch
264

Dengan asumsi nama MemoryStream adalah ms.

Kode ini menuliskan MemoryStream ke file:

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();
}

dan ini membaca file ke MemoryStream:

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);
}

Di .Net Framework 4+, Anda cukup menyalin FileStream ke MemoryStream dan membalikkannya sesederhana ini:

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

Dan Reverse (MemoryStream ke FileStream):

using (FileStream file = new FileStream("file.bin", FileMode.Create, System.IO.FileAccess.Write))
    ms.CopyTo(file);
Ashkan Mobayen Khiabani
sumber
1
Bisakah saya bertanya mengapa Anda menggunakan FileMode.Create dalam sampel read vs FileMode.Open?
Philter
6
Di blok kode pertama, alih-alih secara manual menyalin aliran memori ke array, Anda dapat menggunakan ms.ToArray()fungsi bawaan.
Gman
5
Penting untuk mengatur ms.Position = 0, jika array byte (dan file) akan berisi semua nol.
Gregory Khrapunovich
1
@ Fernando68 konstruk using (...){ }memiliki efek yang persis sama.
Fabricio Araujo
2
Sama seperti peringatan kepada orang lain 'menggunakan (FileStream' dan 'ms.CopyTo (file)' menetapkan posisi untuk akhir file dan Anda perlu mengatur ulang aliran memori sesudahnya.
Rebecca
64

Aliran harus benar-benar dibuang meskipun ada pengecualian (sangat mungkin pada file I / O) - menggunakan klausa adalah pendekatan favorit saya untuk ini, jadi untuk menulis MemoryStream Anda, Anda dapat menggunakan:

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

Dan untuk membacanya kembali:

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);
}

Jika file berukuran besar, maka perlu dicatat bahwa operasi membaca akan menggunakan memori dua kali lebih banyak dari total ukuran file . Salah satu solusi untuk itu adalah membuat MemoryStream dari array byte - kode berikut mengasumsikan Anda tidak akan menulis ke aliran itu.

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

Penelitian saya (di bawah) menunjukkan bahwa buffer internal adalah array byte yang sama dengan yang Anda lewati, sehingga seharusnya menghemat memori.

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

Bagi siapa pun yang mencari versi pendek:

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

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

Jawaban gabungan untuk menulis ke file dapat berupa;

MemoryStream ms = new MemoryStream();    
FileStream file = new FileStream("file.bin", FileMode.Create, FileAccess.Write);
ms.WriteTo(file);
file.Close();
ms.Close();
Berkay Turancı
sumber
15

Simpan ke dalam file

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

Muat dari file

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

dimana

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;
        }
    }
}

Awalnya implementasi kelas ini telah diposting di sini

dan

[Serializable]
public class Car
{
    public string Name;
}
Vadim Gremyachev
sumber
14

Untuk memuat file, saya suka ini jauh lebih baik

MemoryStream ms = new MemoryStream();
using (FileStream fs = File.OpenRead(file))
{
    fs.CopyTo(ms);
}
ProVega
sumber
Jika file dibuka di Microsoft Word - adakah cara untuk membuat aliran memori dari file itu? Saya menerima pesan kesalahan 'file dibuka oleh proses lain'
FrenkyB
@FrenkyB Saya juga sering mengalami hal ini. Jika file terbuka di Word atau aplikasi lain maka Anda tidak bisa melakukannya. Tutup saja file di Word.
Kristopher
@FrenkyB Bisakah Anda melakukan File.Copy? Saya menemukan itu berfungsi, kemudian membaca dari file itu ke dalam aliran dan menghapus file baru ... mengerikan, tetapi tampaknya berhasil.
ridecar2
3

Saya menggunakan Kontrol Panel untuk menambahkan gambar atau bahkan streaming video, tetapi Anda dapat menyimpan gambar di SQL Server sebagai Gambar atau MySQL sebagai largeblob . Kode ini banyak bekerja untuk saya. Saksikan berikut ini.

Di sini Anda menyimpan gambar

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();

Dan di sini Anda dapat memuat, tetapi saya menggunakan Kontrol PictureBox.

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

Semoga bisa membantu.

Leinad
sumber
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();
                        }
                    }
                }
            }

        }
    }
}

Penggunaan: -

ImageWaterMarkBuilder.AddStream(stream).AddWaterMark("").CompileAndSave(filePath);
Ragesh Punathil
sumber