/ / स्ट्रीमरडर और EBCDIC के साथ अजीब व्यवहार: क्यों? - सी #, .नेट, चरित्र-एन्कोडिंग, स्ट्रीमराइडर, इबेडिक

StreamReader और EBCDIC के साथ अजीब व्यवहार: क्यों? - सी #, .नेट, चरित्र-एन्कोडिंग, स्ट्रीमराइडर, इबेडिक

पृष्ठभूमि: मुझे एक एप्लिकेशन लिखना है जो खराब डेटा वाली EBCDIC फ़ाइल को बाइनरी डेटा के साथ लेता है जो ASCII लाइन टर्मिनेटर का उपयोग करता है, और कभी-कभी बाइनरी डेटा में ASCII CRLF होता है जो लाइन को गलत तरीके से विभाजित करने का कारण बनता है। मुझे इस पुराने फ़ाइल प्रारूप को लेने और प्रत्येक रिकॉर्ड के अंत में CRLFs को छोड़ने की आवश्यकता है।

ऐसा लगता है कि एक का उपयोग कर StreamReader साथ में IBM037 एन्कोडिंग का कारण बनता है ReadLine() केवल पढ़ने के लिए विधि r इसके बजाय लाइन के अंत के रूप में rn जैसा कि मुझे उम्मीद है, इसलिए हर स्ट्रिंग (पहली के बाद) मुझे वापस मिल जाएगी ReadLine LF से शुरू होता है (0A ASCII में)।

नमूना कार्यक्रम जो समस्या को पुन: पेश करता है:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

class Program
{
static void Main(string[] args)
{
//generate example EBCDIC data
List<byte> bytes = new List<byte>();
Encoding EBCDIC = Encoding.GetEncoding("IBM037");
bytes.AddRange(Encoding.Convert(Encoding.ASCII, EBCDIC, Encoding.ASCII.GetBytes("Some nice ascii text")));
bytes.AddRange(new byte[] { (byte)"r", (byte)"n" });
bytes.AddRange(Encoding.Convert(Encoding.ASCII, EBCDIC, Encoding.ASCII.GetBytes("Some more nice ascii text")));

//read it using StreamReader
using(MemoryStream ms = new MemoryStream(bytes.ToArray()))
using (StreamReader reader = new StreamReader(ms, EBCDIC))
{
string line = string.Empty;
while ((line = reader.ReadLine()) != null)
{
EBCDIC.GetBytes(line).ToList().ForEach(c => Console.Write(c));
Console.WriteLine();
}
}
Console.ReadLine();
}
}

आउटपुट निम्नानुसार होना चाहिए:

226150148133641491371311336412916213113713764163133167163
1022615014813364148150153133641491371311336412916213113713764163133167163

दूसरी पंक्ति की शुरुआत में वह 10 नहीं होनी चाहिए, क्योंकि वह CRLF अनुक्रम से LF है।

की मेरी समझ ReadLine तरीका यह था कि:

एक पंक्ति को वर्णों के अनुक्रम के रूप में परिभाषित किया गया हैएक पंक्ति फ़ीड ("एन"), एक गाड़ी वापसी ("आर"), या एक गाड़ी फ़ीड के तुरंत बाद एक लाइन फ़ीड ("आरएन") के बाद। जो स्ट्रिंग वापस किया जाता है, उसमें समाप्ति गाड़ी वापसी या लाइन फीड नहीं होती है। स्रोत

यह "एनकोडिंग के बारे में कुछ भी नहीं कहता है जो इसे बदल रहा है, इसलिए इसके अनुसार यह मेरे डेटा में पूर्ण सीआरएलएफ को पढ़ना चाहिए न कि केवल सीआर को।

अपडेट: मैंने पहले ही इस समस्या पर काम किया है और डेटा पढ़ने की अपनी पद्धति लागू की है, लेकिन मेरा प्रश्न अभी भी इस प्रकार है: क्यों किया ReadLine यह टिन पर क्या कहता है?

उत्तर:

जवाब के लिए 2 № 1

आप सामान ए (byte)"r" तथा (byte)"n" एक धारा में जो आप बताएं StreamReader EBCDIC में एन्कोड किया गया है।

के लिए मूल्य (byte) "r" 0x0d है, जो ASCII और EBCDIC दोनों में कैरिज रिटर्न के रूप में होता है।

के लिए मूल्य (byte) "n" 0x0a है, जो ASCII में एक पंक्ति फ़ीड है, लेकिन है नहीं EBCDIC में एक पंक्ति फ़ीड।

यदि आप देखते हैं कि EBCDIC एनकोडर वर्ग 0x0a मान को .NET यूनिकोड में कैसे डिकोड करता है char प्रकार, आप पाएंगे कि यूनिकोड का संख्यात्मक मान char 142 (या 0x8e) है। और वह चरित्र एक पंक्ति फ़ीड नहीं है। (मैं नहीं जानता कि यह 142 में क्यों डिकोड हो गया है)।

आप "10" को प्रिंट करना शुरू करते हैंदूसरी पंक्ति इसलिए नहीं है क्योंकि वहाँ एक लाइन फ़ीड है, लेकिन क्योंकि मूल्य 142 के साथ चार्ट को फिर से ईबसीडीआईसी बाइट में वापस मान लिया जा रहा है जिसमें मान 10 (उप-अभिव्यक्ति में) EBCDIC.GetBytes(line))।

तो अपने प्रश्न का सरलता से उत्तर देने के लिए, ReadLine() केवल एक गाड़ी वापसी देखता है, एक पंक्ति वापसी के बाद गाड़ी वापसी नहीं

अपना बदलें while निम्नलिखित की तरह दिखने के लिए लूप:

while ((line = reader.ReadLine()) != null)
{
line.ToList().ForEach(c => { Console.Write(c); Console.Write(" "); });
Console.WriteLine();
line.ToList().ForEach(c => { Console.Write(Convert.ToInt32(c)); Console.Write(" "); });
Console.WriteLine();
EBCDIC.GetBytes(line).ToList().ForEach(c => { Console.Write(c); Console.Write(" "); });
Console.WriteLine();
Console.WriteLine();
Console.WriteLine();
}

और आपको अपने लिए निम्न आउटपुट मिलेगादूसरी पंक्ति, जो वर्णों के रूप में रेखा (EBCDIC से परिवर्तित) प्रदर्शित करती है, उन वर्णों के लिए यूनिकोड मान और अंत में उन वर्णों के मान EBCDIC में बदल गए:

? S o m e   m o r e   n i c e   a s c i i   t e x t
142 83 111 109 101 32 109 111 114 101 32 110 105 99 101 32 97 115 99 105 105 32 116 101 120 116
10 226 150 148 133 64 148 150 153 133 64 149 137 131 133 64 129 162 131 137 137 64 163 133 167 163

उत्तर № 2 के लिए 1

मैं निम्नलिखित चर्चा पर अड़ गया MSDN मंच:

इसके अनुसार इस दस्तावेज़, अनुभाग "EBCDIC लाइनफाइड मैपिंग कारण अमान्य वर्ण ", नीचे के पास, IBM037 में एक पंक्ति के लिए दो कोड हैं फ़ीड, 0x15 और 0x25। .NET 0x25 का उपयोग करता है:

बाइट [] बाइट्स = System.Text.Encoding.GetEncoding ( "IBM037") GetBytes ( "hellorn")।;

मैंने एक और वेब पेज देखा जिसमें इसे 0x15 पर मैप किया गया था। कोई आश्चर्य नहीं कि ASCII जीता ...

के साथ जाँच कर रहा है विकिपीडिया वॉन EBCDIC 037 ने पुष्टि की कि वास्तव में बाइट 21 (0x15) को "न्यूलाइन" और 37 (0x25) "लाइन फीड" के रूप में परिभाषित किया गया है, जहां बाइट 13 (0x0D) के रूप में अच्छा-पुराना "कैरिज रिटर्न" है।

इसलिए ASCII EBCDIC 037 का सबसेट नहीं है।

आपके टेस्ट कोड इस प्रकार त्रुटिपूर्ण हैं जब आप बाइट्स को 0x10 और 0x13 को जोड़ते हैं, जब आपको ऐसा करना हो तो EBCDIC-एन्कोडेड बाइट्स:

bytes.AddRange(new byte[] { (byte)"r", (byte)"n" });

इसके बजाय निम्नलिखित प्रयास करें:

bytes.AddRange(Encoding.Convert(Encoding.ASCII, EBCDIC, Encoding.ASCII.GetBytes(
"Some nice ascii textrnSome more nice ascii text")));

परिणामी बाइट्स पढ़ना, जैसा कि यह होना चाहिए क्योंकि "rn" EBCDIC के लिए बाइट्स 13 और 37 में बदल जाता है। ReadLine() फिर बाइट 37 पर सही ढंग से स्किप हो गया जो EBCDIC "न्यूलाइन" है।

यह है क्योंकि ReadLine() यूनिकोड वर्णों की तुलना करता है, बाइट्स की नहीं। एक EBCDIC "न्यूलाइन" (0x25) बाइट को यूनिकोड वर्ण "n" के रूप में डिकोड किया गया है।

निष्कर्ष

  1. हर चीज़ वैसे ही काम कर रही है जैसी उसे करनी चाहिए।
  2. सभी एन्कोडिंग में एक उपसमूह के रूप में ASCII नहीं है।
  3. ReadLine () यूनिकोड वर्णों के साथ काम करता है, इसलिए यह एक एन्कोडिंग / डिकोडिंग समस्या होनी चाहिए।
  4. अपनी मूल समस्या के इनपुट डेटा की जाँच करें। इसमें अमान्य (EBCDIC के लिए) न्यूलाइन वर्ण हो सकते हैं।