Chuyển đổi Stream thành String và quay lại những gì chúng ta đang thiếu?


162

Tôi muốn nối tiếp các đối tượng thành chuỗi và quay lại.

Chúng tôi sử dụng protobuf-net để biến một đối tượng thành Luồng và quay lại, thành công.

Tuy nhiên, Stream thành chuỗi và trở lại ... không thành công. Sau khi đi qua StreamToStringStringToStream, cái mới Streamkhông được khử lưu huỳnh bởi protobuf-net; nó đưa ra một Arithmetic Operation resulted in an Overflowngoại lệ Nếu chúng ta khử lưu lượng gốc, nó hoạt động.

Phương pháp của chúng tôi:

public static string StreamToString(Stream stream)
{
    stream.Position = 0;
    using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
    {
        return reader.ReadToEnd();
    }
}

public static Stream StringToStream(string src)
{
    byte[] byteArray = Encoding.UTF8.GetBytes(src);
    return new MemoryStream(byteArray);
}

Mã ví dụ của chúng tôi sử dụng hai:

MemoryStream stream = new MemoryStream();
Serializer.Serialize<SuperExample>(stream, test);
stream.Position = 0;
string strout = StreamToString(stream);
MemoryStream result = (MemoryStream)StringToStream(strout);
var other = Serializer.Deserialize<SuperExample>(result);

1
Không nên Stream là MemoryStrea?
Ehsan

Câu trả lời:


60

Điều này là rất phổ biến nhưng rất sai lầm. Dữ liệu Protobuf không phải là dữ liệu chuỗi. Nó chắc chắn không phải là ASCII. Bạn đang sử dụng mã hóa ngược . Một mã hóa văn bản chuyển:

  • một chuỗi tùy ý để định dạng byte
  • định dạng byte cho chuỗi gốc

Bạn không có "byte định dạng". Bạn có byte tùy ý . Bạn cần sử dụng một cái gì đó giống như mã hóa base-n (thường là: base-64). Chuyển khoản này

  • byte tùy ý cho một chuỗi được định dạng
  • một chuỗi được định dạng cho các byte gốc

nhìn vào Convert.ToBase64String và Convert. TừBase64String


1
bạn có thể sử dụng một BinaryFormatter, tương tự như ví dụ kỳ lạ này ?
drzaus

@drzaus hm ... có thể không:> "Bất kỳ nhân vật thay thế không ghép đôi nào bị mất trong tuần tự nhị phân"
drzaus

210

Tôi vừa thử nghiệm điều này và hoạt động tốt.

string test = "Testing 1-2-3";

// convert string to stream
byte[] byteArray = Encoding.ASCII.GetBytes(test);
MemoryStream stream = new MemoryStream(byteArray);

// convert stream to string
StreamReader reader = new StreamReader(stream);
string text = reader.ReadToEnd();

Nếu streamđã được viết thành, bạn có thể muốn tìm kiếm lại từ đầu trước khi đọc văn bản:stream.Seek(0, SeekOrigin.Begin);


Và đừng quên một khối sử dụng xung quanh trình đọc StreamReader = new StreamReader (luồng);
PRman

7

chuyển đổi UTF8 MemoryStream sang String:

var res = Encoding.UTF8.GetString(stream.GetBuffer(), 0 , (int)stream.Length)

2
Sử dụng ToArray () thay thế. Bộ đệm có thể lớn hơn kích thước của dữ liệu được sử dụng. ToArray () trả về một bản sao của dữ liệu với kích thước chính xác. var array = stream.ToArray(); var str = Encoding.UTF8.GetString(array, 0, array.Length);. Xem thêm msdn.microsoft.com/en-us/l
Library / Mạnh

1
@Mortennobel ToArray()phân bổ một mảng mới trong bộ nhớ và sao chép dữ liệu từ bộ đệm, điều này có thể có ý nghĩa nghiêm trọng nếu bạn đang xử lý nhiều dữ liệu.
Levi Botelho

Lưu ý việc sử dụng stream. Chiều dài, thay vì stream.GetBuffer (). Chiều dài. Và Levi đã lưu ý chính xác lý do không sử dụng ToArray ().
Wolfgang Grinfeld

5

Khi bạn kiểm tra thử với UTF8luồng Mã hóa như bên dưới

var stream = new MemoryStream();
var streamWriter = new StreamWriter(stream, System.Text.Encoding.UTF8);
Serializer.Serialize<SuperExample>(streamWriter, test);


2

Tôi đã viết một phương thức hữu ích để gọi bất kỳ hành động nào cần thực hiện StreamWritervà viết nó ra một chuỗi thay thế. Phương pháp là như thế này;

static void SendStreamToString(Action<StreamWriter> action, out string destination)
{
    using (var stream = new MemoryStream())
    using (var writer = new StreamWriter(stream, Encoding.Unicode))
    {
        action(writer);
        writer.Flush();
        stream.Position = 0;
        destination = Encoding.Unicode.GetString(stream.GetBuffer(), 0, (int)stream.Length);
    }
}

Và bạn có thể sử dụng nó như thế này;

string myString;

SendStreamToString(writer =>
{
    var ints = new List<int> {1, 2, 3};
    writer.WriteLine("My ints");
    foreach (var integer in ints)
    {
        writer.WriteLine(integer);
    }
}, out myString);

Tôi biết điều này có thể được thực hiện dễ dàng hơn nhiều với a StringBuilder, vấn đề là bạn có thể gọi bất kỳ phương thức nào có a StreamWriter.


1

Tôi muốn nối tiếp các đối tượng thành chuỗi và quay lại.

Khác với các câu trả lời khác, nhưng cách đơn giản nhất để thực hiện chính xác điều đó đối với hầu hết các loại đối tượng là XmlSerializer:

        Subject subject = new Subject();
        XmlSerializer serializer = new XmlSerializer(typeof(Subject));
        using (Stream stream = new MemoryStream())
        {
            serializer.Serialize(stream, subject);
            // do something with stream
            Subject subject2 = (Subject)serializer.Deserialize(stream);
            // do something with subject2
        }

Tất cả các thuộc tính công khai của bạn về các loại được hỗ trợ sẽ được tuần tự hóa. Ngay cả một số cấu trúc bộ sưu tập cũng được hỗ trợ và sẽ chuyển xuống các thuộc tính của đối tượng phụ. Bạn có thể kiểm soát cách thức tuần tự hóa hoạt động với các thuộc tính trên thuộc tính của bạn.

Điều này không hoạt động với tất cả các loại đối tượng, một số loại dữ liệu không được hỗ trợ để tuần tự hóa, nhưng nhìn chung nó khá mạnh mẽ và bạn không phải lo lắng về mã hóa.


0

Trong usecase nơi bạn muốn tuần tự hóa / giải tuần tự hóa POCO, thư viện JSON của Newtonsoft thực sự tốt. Tôi sử dụng nó để duy trì các POCO trong SQL Server dưới dạng các chuỗi JSON trong trường nvarchar. Hãy cẩn thận là vì nó không thực sự khử / tuần tự hóa, nó sẽ không bảo vệ các thành viên riêng tư / được bảo vệ và phân cấp lớp.

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.