บันทึกและโหลด MemoryStream ไปยัง / จากไฟล์


281

ฉันกำลังทำให้โครงสร้างเป็นอนุกรมMemoryStreamและฉันต้องการบันทึกและโหลดโครงสร้างที่ทำให้เป็นอนุกรม

ดังนั้นวิธีบันทึกMemoryStreamลงในไฟล์และโหลดกลับจากไฟล์ได้อย่างไร


หากคุณต้องการบันทึกลงไฟล์ทำไมคุณใช้MemoryStream?
Oded

@Oded สิ่งที่ฉันควรใช้? คุณยกตัวอย่างให้ฉันได้ไหม
Mahdi Ghiasi

คำตอบ:


365

คุณสามารถใช้MemoryStream.WriteToหรือStream.CopyTo(ได้รับการสนับสนุนในกรอบงานเวอร์ชัน 4.5.2, 4.5.1, 4.5, 4) วิธีการเขียนเนื้อหาของหน่วยความจำสตรีมไปยังสตรีมอื่น

memoryStream.WriteTo(fileStream);

ปรับปรุง:

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

13
memoryStream.CopyTo ดูเหมือนจะไม่ทำงานสำหรับฉันในขณะที่ WriteTo ทำ ฉันคิดว่าอาจเป็นเพราะความทรงจำของฉันสตรีมตำแหน่งไม่ใช่ 0
Mark Adamson

10
ใช่ว่าถูกต้อง ความแตกต่างระหว่างพวกเขาคือ CopyTo คัดลอกจากสิ่งที่ตำแหน่งปัจจุบันแทนที่จะเป็นเสมอจากจุดเริ่มต้นเช่น WriteTo ทำ
AnorZaken

6
การเพิ่ม[file|memory]Stream.Seek(0, SeekOrigin.Begin);ก่อนCopyToจะตั้งตำแหน่งปัจจุบันเป็น 0 เพื่อที่CopyToจะคัดลอกสตรีมที่สมบูรณ์
Martin Backasch

264

สมมติว่าชื่อ MemoryStream คือ msคือ

รหัสนี้เขียน MemoryStream ลงในไฟล์:

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

และสิ่งนี้จะอ่านไฟล์ไปยัง 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);
}

ใน. Net Framework 4+ คุณสามารถคัดลอก FileStream ไปที่ MemoryStream และย้อนกลับได้ง่ายเช่นนี้

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

และย้อนกลับ (MemoryStream ถึง FileStream):

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

1
ฉันจะถามได้ไหมว่าทำไมคุณถึงใช้ FileMode.Create ในตัวอย่างการอ่าน vs FileMode.Open
Philter

6
ในบล็อกรหัสแรกแทนที่จะคัดลอกสตรีมหน่วยความจำไปยังอาร์เรย์ด้วยตนเองคุณสามารถใช้ms.ToArray()ฟังก์ชันในตัว
Gman

5
สิ่งสำคัญคือการตั้งค่า ms.Position = 0 มิฉะนั้นอาร์เรย์ไบต์ (และไฟล์) จะมีศูนย์ทั้งหมด
เกรกอรี่ Khrapunovich

1
@ Fernando68 โครงสร้างusing (...){ }มีผลเหมือนกันทุกประการ
Fabricio Araujo

2
เช่นเดียวกับคำเตือนให้ผู้อื่น 'ใช้ (FileStream' และ 'ms.CopyTo (ไฟล์)' กำหนดตำแหน่งจนถึงจุดสิ้นสุดของไฟล์และคุณต้องรีเซ็ต memorystream หลังจากนั้น
Rebecca

64

สตรีมควรกำจัดอย่างแท้จริงแม้ว่าจะมีข้อยกเว้น (น่าจะเป็นไฟล์ I / O) - การใช้ส่วนคำสั่งเป็นวิธีที่ฉันโปรดปรานสำหรับสิ่งนี้ดังนั้นสำหรับการเขียน MemoryStream ของคุณคุณสามารถใช้:

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

และสำหรับการอ่านกลับ:

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

ถ้าไฟล์ที่มีขนาดใหญ่แล้วมันเป็นที่น่าสังเกตว่าการดำเนินการอ่านจะใช้สองเท่าของหน่วยความจำมากขนาดแฟ้มทั้งหมด ทางออกหนึ่งคือการสร้าง MemoryStream จากอาร์เรย์ไบต์ - รหัสต่อไปนี้อนุมานว่าคุณจะไม่เขียนไปยังสตรีมนั้น

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

การวิจัยของฉัน (ด้านล่าง) แสดงว่าบัฟเฟอร์ภายในเป็นอาร์เรย์ไบต์เดียวกับที่คุณส่งผ่านดังนั้นจึงควรบันทึกหน่วยความจำ

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

41

สำหรับทุกคนที่กำลังมองหาเวอร์ชั่นสั้น:

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

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

20

คำตอบรวมสำหรับการเขียนไปยังไฟล์สามารถ;

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

15

บันทึกลงในไฟล์

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

โหลดจากไฟล์

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

ที่ไหน

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

แต่เดิมการใช้งานของคลาสนี้ถูกโพสต์ที่นี่

และ

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

14

สำหรับการโหลดไฟล์ฉันชอบสิ่งนี้ดีกว่ามาก

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

หากเปิดไฟล์ใน Microsoft Word - มีวิธีสร้างสตรีมหน่วยความจำจากไฟล์นั้นหรือไม่? ฉันได้รับข้อผิดพลาด 'ไฟล์ถูกเปิดโดยกระบวนการอื่น'
FrenkyB

@FrenkyB ฉันยังเจอเรื่องนี้มาก หากคุณมีไฟล์ที่เปิดอยู่ใน Word หรือแอปอื่น ๆ คุณจะไม่สามารถทำได้ เพียงแค่ปิดไฟล์ใน Word
Kristopher

@FrenkyB คุณสามารถทำ File.Copy ได้หรือไม่ ฉันพบว่ามันใช้งานได้จากนั้นอ่านจากไฟล์นั้นลงในสตรีมและลบไฟล์ใหม่ ... น่ากลัว แต่ดูเหมือนว่าจะใช้งานได้
ridecar2

3

ฉันใช้ 'แผงควบคุม' เพื่อเพิ่มรูปภาพหรือแม้แต่วิดีโอสตรีม แต่คุณสามารถบันทึกรูปภาพบน SQL Server เป็นรูปภาพหรือ MySQL เป็นบล็อกขนาดใหญ่ได้ รหัสนี้เหมาะกับฉันมาก ลองดูสิ

ที่นี่คุณบันทึกภาพ

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

และที่นี่คุณสามารถโหลดได้ แต่ฉันใช้ PictureBox Control

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

หวังว่าจะช่วย


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

        }
    }
}

การใช้งาน: -

ImageWaterMarkBuilder.AddStream(stream).AddWaterMark("").CompileAndSave(filePath);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.