قراءة السطر من صفيف البايت (لا يتم تحويل صفيف البايت إلى سلسلة)

StackOverflow https://stackoverflow.com/questions/492454

سؤال

لدي مصفوفة بايت أقرأها من NetworkStream.تخبر أول بايتتين طول الحزمة التالية ثم تتم قراءة الحزمة في مصفوفة بايت بهذا الطول.تحتوي البيانات التي أحتاج إلى قراءتها من مصفوفة NetworkStream/byte على عدد قليل من السلاسل، على سبيل المثال.بيانات متغيرة الطول منتهية بأحرف أسطر جديدة، وبعض الحقول ذات العرض الثابت مثل البايتات والأطوال.لذلك، شيء من هذا القبيل:

// I would have delimited these for clarity but I didn't want
// to imply that the stream was delimited because it's not.
StringbyteStringStringbytebytebytelonglongbytelonglong

أعرف (ولدي رأي آخر) تنسيق حزمة البيانات القادمة، وما يجب علي فعله هو قراءة "سطر" لكل قيمة سلسلة، ولكن قراءة عدد ثابت من البايتات للبايتات والأطوال.الحل المقترح حتى الآن هو استخدام ملف while حلقة لقراءة البايتات في صفيف بايت مؤقت حتى يكون هناك حرف سطر جديد.ثم قم بتحويل البايتات إلى سلسلة.يبدو هذا الأمر مبتذلاً بالنسبة لي، لكنني لا أرى طريقة أخرى واضحة.أدرك أنني يمكن أن تستخدم StreamReader.ReadLine() ولكن ذلك سيتضمن دفقًا آخر ولدي بالفعل ملف NetworkStream.ولكن إذا كان هذا هو الحل الأفضل، سأجربه.

الخيار الآخر الذي فكرت فيه هو أن أطلب من فريق الواجهة الخلفية الخاص بي كتابة بايت أو اثنين لأطوال قيم السلسلة تلك حتى أتمكن من قراءة الطول ثم قراءة السلسلة بناءً على الطول المحدد.

لذا، كما ترون، لدي بعض الخيارات لكيفية القيام بذلك، وأود الحصول على مدخلاتكم حول ما تعتبرونه أفضل طريقة للقيام بذلك.هذا هو الكود الذي لدي الآن لقراءته في الحزمة بأكملها كسلسلة.الخطوة التالية هي تقسيم الحقول المختلفة للحزمة والقيام بأعمال البرمجة الفعلية التي يجب القيام بها، وإنشاء الكائنات، وتحديث واجهة المستخدم، وما إلى ذلك.بناءً على البيانات الموجودة في الحزمة.

string line = null;  
while (stream.DataAvailable)
{  
    //Get the packet length;  
    UInt16 packetLength = 0;  
    header = new byte[2];  
    stream.Read(header, 0, 2);  
    // Need to reverse the header array for BitConverter class if architecture is little endian.  
    if (BitConverter.IsLittleEndian)
        Array.Reverse(header);  
    packetLength = BitConverter.ToUInt16(header,0);

    buffer = new byte[packetLength];
    stream.Read(buffer, 0, BitConverter.ToUInt16(header, 0));
    line = System.Text.ASCIIEncoding.ASCII.GetString(buffer);
    Console.WriteLine(line);
}
هل كانت مفيدة؟

المحلول

شخصيا سأفعل

  1. ضع INT16 في بداية الأوتار ، حتى تعرف المدة التي ستكون عليها ، و
  2. استخدم فئة IO.BinaryReader للقيام بالقراءة ، وسوف "قراءة" ، ints ، الأوتار ، chars إلخ إلى متغير على سبيل المثالسوف يقوم BinReader.ReadInt16() بقراءة وحدتي بايت، وإرجاع int16 الذي يمثلونه، ونقل وحدتي بايت في الدفق

أتمنى أن يساعدك هذا.

ملاحظة.كن حذرًا عند استخدام طريقة ReadString، فهي تفترض أن السلسلة مُلحقة بأعداد صحيحة مخصصة مكونة من 7 بتات، أي.أنه تم كتابته بواسطة فئة BinaryWriter.ما يلي هو من هذا CodeGuru بريد

تحتوي فئة BinaryWriter على طريقتان لكتابة سلاسل:طريقة الكتابة الزائدة () وطريقة WriteString ().السابق يكتب السلسلة على أنها دفق من البايتات وفقًا للترميز الذي يستخدمه الفصل.تستخدم طريقة WriteString () أيضًا الترميز المحدد ، لكنها تسبق دفق السلسلة من البايتات مع الطول الفعلي للسلسلة.تتم قراءة هذه السلاسل المسبقة مرة أخرى عبر binaryReader.ReadString ().

الشيء المثير للاهتمام حول قيمة الطول ، حيث يتم استخدام عدد قليل من البايتات قدر الإمكان لعقد هذا الحجم ، يتم تخزينه كنوع يسمى عدد صحيح مشفرة 7 بت.إذا تم استخدام الطول في 7 بتات بايت واحد ، إذا كان أكبر من هذا ، فسيتم تعيين البتات العالية على البايت الأول ويتم إنشاء بايت ثانية عن طريق تحويل القيمة بمقدار 7 بت.يتم تكرار ذلك مع بايت متتالية حتى يكون هناك ما يكفي من البايتات للاحتفاظ بالقيمة.تُستخدم هذه الآلية للتأكد من أن الطول لا يصبح جزءًا كبيرًا من الحجم الذي يتم تناوله بواسطة السلسلة المسلسل.لدى BinaryWriter و BinaryReader طرق لقراءة وكتابة الأعداد الصحيحة المشفرة 7 بت ، لكنها محمية وبالتالي لا يمكنك استخدامها إلا إذا اشتقت من هذه الفئات.

نصائح أخرى

سأختار السلاسل ذات البادئة الطولية.سيجعل حياتك أسهل كثيرًا، ويعني أنه يمكنك تمثيل السلاسل مع فواصل الأسطر.بعض التعليقات على التعليمات البرمجية الخاصة بك بالرغم من ذلك:

  • لا تستخدم Stream.DataAvailable.فقط لأنه لا توجد بيانات متاحة الآن لا يعني أنك قرأت نهاية الدفق.
  • ما لم تكن متأكدًا تمامًا من أنك لن تحتاج أبدًا إلى نص يتجاوز ASCII، فلا تستخدم ASCIIEncoding.
  • لا تفترض أن Stream.Read سوف يقرأ جميع البيانات التي تطلبها منه. دائماً تحقق من قيمة الإرجاع.
  • يجعل BinaryReader الكثير من هذا أسهل كثيرًا (بما في ذلك السلاسل ذات البادئة الطولية والقراءة التي تتكرر حتى تتم قراءة ما طلبته منه)
  • أنت تقوم بالاتصال بـ BitConverter.ToUInt16 مرتين على نفس البيانات.لماذا؟
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top