Lưu và tải MemoryStream đến / từ một tệp


281

Tôi đang tuần tự hóa một cấu trúc thành một MemoryStreamvà tôi muốn lưu và tải cấu trúc nối tiếp.

Vì vậy, làm thế nào để lưu a MemoryStreamvào một tập tin và cũng tải lại từ tập tin?


Nếu bạn cần lưu vào một tập tin, tại sao bạn lại sử dụng MemoryStream?
Oded

@Oded Tôi nên dùng gì? Bạn có thể cho tôi một ví dụ?
Mahdi Ghiasi

Câu trả lời:


365

Bạn có thể sử dụng MemoryStream.WriteTohoặc Stream.CopyTo(được hỗ trợ trong các phiên bản khung 4.5.2, 4.5.1, 4.5, 4) để ghi nội dung của luồng bộ nhớ vào luồng khác.

memoryStream.WriteTo(fileStream);

Cập nhật:

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

13
memoryStream.CopyTo dường như không hoạt động với tôi, trong khi WriteTo thì có. Tôi nghĩ có lẽ đó là do trí nhớ của tôiStream.P Vị trí không phải là 0
Đánh dấu Adamson

10
Vâng, đó là chính xác. Sự khác biệt giữa chúng là CopyTo sao chép từ bất kỳ vị trí hiện tại nào thay vì luôn luôn bắt đầu như WriteTo.
AnorZaken

6
Thêm [file|memory]Stream.Seek(0, SeekOrigin.Begin);trước CopyTosẽ đặt vị trí hiện tại thành 0, do đó CopyTosẽ sao chép luồng hoàn chỉnh.
Martin Backasch

263

Giả sử tên MemoryStream là ms.

Mã này ghi MemoryStream vào một tệp:

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

và điều này đọc một tập tin vào 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);
}

Trong .Net Framework 4+, bạn chỉ cần sao chép FileStream sang MemoryStream và đảo ngược đơn giản như sau:

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

Và ngược lại (MemoryStream thành FileStream):

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

1
Tôi có thể hỏi tại sao bạn sử dụng FileMode.Create trong mẫu đọc so với FileMode.Open không?
Philter

6
Trong khối mã đầu tiên, thay vì sao chép thủ công luồng bộ nhớ vào mảng, bạn có thể sử dụng ms.ToArray()chức năng tích hợp.
Gman

5
Điều quan trọng là đặt ms.Pocation = 0, nếu không thì mảng byte (và tệp) sẽ chứa tất cả các số không.
Gregory Khrapunovich

1
@ Fernando68 các cấu trúc using (...){ }có tác dụng chính xác như nhau.
Fabricio Araujo

2
Giống như một cảnh báo cho người khác 'bằng cách sử dụng (FileStream' và 'ms.CopyTo (tệp)' đặt vị trí cuối của tệp và bạn cần đặt lại dòng bộ nhớ sau đó.
Rebecca

63

Luồng thực sự nên được xử lý ngay cả khi có ngoại lệ (rất có thể trên tệp I / O) - sử dụng mệnh đề là cách tiếp cận yêu thích của tôi cho việc này, vì vậy để viết MemoryStream, bạn có thể sử dụng:

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

Và để đọc lại:

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

Nếu các tệp lớn, thì đáng chú ý là thao tác đọc sẽ sử dụng gấp đôi bộ nhớ so với tổng kích thước tệp . Một giải pháp cho vấn đề đó là tạo MemoryStream từ mảng byte - đoạn mã sau giả sử bạn sẽ không ghi vào luồng đó.

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

Nghiên cứu của tôi (bên dưới) cho thấy bộ đệm bên trong là cùng một mảng byte khi bạn truyền nó, vì vậy nó sẽ tiết kiệm bộ nhớ.

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

41

Đối với bất cứ ai tìm kiếm các phiên bản ngắn:

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

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

20

Câu trả lời kết hợp để ghi vào một tập tin có thể là;

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

15

Lưu vào một tập tin

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

Tải từ một tập tin

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

Ở đâu

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

Ban đầu việc thực hiện lớp này đã được đăng ở đây

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

14

Để tải một tập tin, tôi thích điều này tốt hơn rất nhiều

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

Nếu tệp được mở trong Microsoft Word - có cách nào để tạo luồng bộ nhớ từ tệp đó không? Tôi đang nhận được một lỗi 'tập tin được mở bởi một quy trình khác'
FrenkyB

@FrenkyB Tôi cũng chạy vào đây rất nhiều. Nếu bạn mở tệp trong Word hoặc một số ứng dụng khác thì bạn không thể thực hiện được. Chỉ cần đóng tệp trong Word.
Kristopher

@FrenkyB Bạn có thể làm File.Copy không? Tôi đã thấy rằng để làm việc, sau đó đọc từ tệp đó vào một luồng và xóa tệp mới ... thật kinh khủng, nhưng dường như hoạt động.
Ridecar2

3

Tôi sử dụng Bảng điều khiển để thêm hình ảnh hoặc thậm chí truyền phát video, nhưng bạn có thể lưu hình ảnh trên SQL Server dưới dạng Hình ảnh hoặc MySQL dưới dạng lớn . Mã này làm việc cho tôi rất nhiều. Kiểm tra nó ra.

Ở đây bạn lưu hình ảnh

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

Và ở đây bạn có thể tải, nhưng tôi đã sử dụng Điều khiển PictureBox.

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

Hy vọng giúp.


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

        }
    }
}

Sử dụng :-

ImageWaterMarkBuilder.AddStream(stream).AddWaterMark("").CompileAndSave(filePath);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.