스트림을 문자열로 변환 및 다시 변환 ... 우리가 무엇을 놓치고 있습니까?


162

객체를 문자열로 다시 직렬화하고 싶습니다.

우리는 protobuf-net을 사용하여 객체를 스트림으로 변환하고 성공적으로 되돌립니다.

그러나 Stream to string and back ... 그렇게 성공하지 못했습니다. StreamToStringand을 거친 후 StringToStream, 새로운 Stream것은 protobuf-net에 의해 deserialize되지 않습니다; Arithmetic Operation resulted in an Overflow예외 가 발생합니다. 원래 스트림을 역 직렬화하면 작동합니다.

우리의 방법 :

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

이 두 가지를 사용하는 예제 코드 :

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
Stream이 MemoryStrea가 아니어야합니까?
Ehsan

답변:


60

이것은 매우 일반적이지만 너무나 잘못되었습니다. 프로토 타입 데이터는 문자열 데이터가 아닙니다. 확실히 ASCII가 아닙니다. 인코딩을 거꾸로 사용하고 있습니다 . 텍스트 인코딩은 다음을 전송합니다.

  • 포맷 된 바이트에 대한 임의의 문자열
  • 원래 문자열에 대한 형식화 된 바이트

"포맷 된 바이트"가 없습니다. 당신은 임의의 바이트 . base-n (일반적으로 base-64) 인코딩과 같은 것을 사용해야합니다. 이 전송

  • 서식이 지정된 문자열에 대한 임의 바이트
  • 원래 바이트에 대한 형식화 된 문자열

Convert.ToBase64String 및 Convert를보십시오. FromBase64String


1
BinaryFormatter이상한 예제비슷한를 사용할 수 있습니까?
drzaus

@drzaus hm ... 아마도 :> "쌍을 이루지 않은 대리 문자는 이진 직렬화에서 손실됩니다"
drzaus

211

방금 이것을 테스트하고 정상적으로 작동합니다.

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

경우 stream이미 기록 된, 당신은 텍스트를 읽기 전에 먼저 이전부터 추구 할 수 있습니다 :stream.Seek(0, SeekOrigin.Begin);


그리고 StreamReader reader = new StreamReader (stream);
PRMan

7

UTF8 MemoryStream에서 문자열로의 변환 :

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

2
대신 ToArray ()를 사용하십시오. 버퍼는 사용 된 데이터의 크기보다 클 수 있습니다. ToArray ()는 올바른 크기의 데이터 복사본을 반환합니다. var array = stream.ToArray(); var str = Encoding.UTF8.GetString(array, 0, array.Length);. 참조 msdn.microsoft.com/en-us/library/...
Mortennobel

1
@Mortennobel ToArray()은 메모리에 새 배열을 할당하고 버퍼에서 데이터를 복사하므로 많은 데이터를 처리하는 경우 심각한 영향을 줄 수 있습니다.
Levi Botelho

stream.GetBuffer (). Length 대신 stream.Length를 사용하십시오. 그리고 Levi는 ToArray ()를 사용하지 않는 이유를 올바르게 기록했습니다.
볼프강 그린 펠트

5

테스트 할 때 UTF8아래와 같이 Encode stream을 사용해보십시오

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


2

나는 a를 취하는 StreamWriter문자열을 대신 하는 액션을 호출하는 유용한 메소드를 작성했다. 방법은 다음과 같습니다.

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

이런 식으로 사용할 수 있습니다.

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

나는 이것을 사용하여 훨씬 쉽게 할 수 있다는 것을 알고 있습니다 StringBuilder. 요점은을 취하는 모든 메소드를 호출 할 수 있다는 것 StreamWriter입니다.


1

객체를 문자열로 다시 직렬화하고 싶습니다.

다른 답변과는 다르지만 대부분의 개체 유형에 대해 정확하게 수행하는 가장 간단한 방법은 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
        }

지원되는 유형의 모든 공용 속성이 직렬화됩니다. 일부 콜렉션 구조도 지원되며 하위 오브젝트 특성으로 터널링됩니다. 속성의 특성 으로 직렬화가 작동하는 방식을 제어 할 수 있습니다 .

이것은 모든 객체 유형에서 작동하지는 않지만 일부 데이터 유형은 직렬화를 지원하지 않지만 전반적으로 매우 강력하며 인코딩에 대해 걱정할 필요가 없습니다.


0

POCO를 직렬화 / 직렬화하려는 유스 케이스에서 Newtonsoft의 JSON 라이브러리는 정말 좋습니다. SQL Server 내의 POCO를 nvarchar 필드에 JSON 문자열로 유지하는 데 사용합니다. 주의 사항은 진정한 de / serialization이 아니기 때문에 개인 / 보호 멤버 및 클래스 계층 구조를 보존하지 않는다는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.