การแปลง Stream เป็น String และ back …สิ่งที่ขาดหายไปคืออะไร?


162

ฉันต้องการทำให้วัตถุเป็นสตริงและกลับเป็นอันดับ

เราใช้ protobuf-net เพื่อเปลี่ยนวัตถุให้เป็นกระแสข้อมูลและย้อนกลับได้สำเร็จ

อย่างไรก็ตามสตรีมไปยังสตริงและสำรอง ... ไม่ประสบความสำเร็จ หลังจากผ่านไปStreamToStringและStringToStreamใหม่Streamไม่ได้ deserialized โดย protobuf สุทธิ; มันทำให้เกิด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
ไม่ควรสตรีมเป็น MemoryStrea
Ehsan

คำตอบ:


60

นี่เป็นเรื่องธรรมดามาก แต่ผิดอย่างยิ่ง ข้อมูล Protobuf ไม่ใช่ข้อมูลสตริง แน่นอนว่าไม่ใช่ ASCII คุณกำลังใช้การเข้ารหัสถอยหลัง การถ่ายโอนการเข้ารหัสข้อความ:

  • สตริงที่กำหนดเองเป็นไบต์ที่จัดรูปแบบ
  • ไบต์ที่จัดรูปแบบเป็นสตริงต้นฉบับ

คุณไม่มี "รูปแบบไบต์" คุณมีไบต์โดยพลการ คุณจำเป็นต้องใช้บางอย่างเช่นการเข้ารหัสแบบฐาน -n โอนนี้

  • ไบต์ที่กำหนดเองเป็นสตริงที่จัดรูปแบบ
  • สตริงที่จัดรูปแบบเป็นไบต์ดั้งเดิม

ดูที่ Convert.ToBase64String และแปลง FromBase64String


1
คุณสามารถใช้ a BinaryFormatter, คล้ายกับตัวอย่างแปลก ๆนี้ได้ไหม
drzaus

@drzaus อืม ... อาจจะไม่:> "ตัวละครตัวแทนที่ไม่มีคู่ใดหายไปในการทำให้เป็นเลขฐานสอง"
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 = StreamReader ใหม่ (สตรีม)
PRMan

7

แปลง UTSt8 MemoryStream เป็น String:

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

หมายเหตุการใช้สตรีมความยาวมากกว่าสตรีม GetBuffer () ความยาว และเลวีก็จดบันทึกเหตุผลที่ไม่ได้ใช้ ToArray () อย่างถูกต้อง
Wolfgang Grinfeld

5

เมื่อคุณทดสอบลองใช้UTF8สตรีมเข้ารหัสเช่นด้านล่าง

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


2

ฉันเขียนวิธีที่มีประโยชน์ในการเรียกการกระทำใด ๆ ที่ดำเนินการ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

ในกรณีที่คุณต้องการทำให้เป็นอนุกรม / deserialize POCOs ไลบรารี JSON ของ Newtonsoft นั้นดีจริงๆ ฉันใช้เพื่อคงอยู่ POCO ภายใน SQL Server เป็นสตริง JSON ในเขตข้อมูล nvarchar Caveat เป็นเพราะมันไม่เป็นความจริง de / serialization มันจะไม่รักษาสมาชิกส่วนตัว / ป้องกันและลำดับชั้น

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