Þeir sem hafa verið að vandræðast með textaskrár í .NET umhverfinu hafa eflaust lent í vandræðum tengdum íslenskum stöfum og fleira því líkt. Ástæðan fyrir þessu er mismunandi kóðun á stöfunum. .NET notast við UTF-8 sem sjálfgefna stafakóðun sem er mjög gott mál, en vandamálið er að Windows XP og Windows 2000 að ég held, notast við UTF-7 ef Ísland er valið í “regional settings”.
.Net inniheldur ágætis aðferð til að styðja flest allar kóðanir, og einfalt mál er að sækja “default” kóðun stýrikerfisins, t.d. með því að keyra System.Text.Encoding.Default en það skilar okkur til baka kóðara sem Windowsið notar sem “Default”.
Þetta er ekki vandamál í flestum tilfellum, en þar sem er komið ósamræmi við kóðun í .NET og svo í Windows, þá getur reynst nauðsynlegt að styðja báðar kóðanirnar. Ég hef ekki fundið aðferð í .NET til að fatta sjálfvirkt hvaða kóðun textaskjal notar, og hefur því oft reynst vandamál að fá þessi skjöl til að birtast rétt.
Windows API-ið inniheldur aftur á móti fall sem reynir að fatta þetta, það er ekki 100% öruggt, en það í það minnsta betra en ekkert :D Nú ætla ég að sýna hvernig hægt er að nota þetta fall.
Í fyrsta lagi þarf að bæta við using klausuna:
using System.Runtime.InteropServices;
og svo skilgreina nokkrar breytur. Ég set þær sem member breytur á klasann.
public static int IS_TEXT_UNICODE_ASCII16 = 0x1;
public static int IS_TEXT_UNICODE_CONTROLS = 0x4;
public static int IS_TEXT_UNICODE_DBCS_LEADBYTE = 0x400;
public static int IS_TEXT_UNICODE_ILLEGAL_CHARS = 0x100;
public static int IS_TEXT_UNICODE_NOT_ASCII_MASK = 0xF000;
public static int IS_TEXT_UNICODE_NOT_UNICODE_MASK = 0xF00;
public static int IS_TEXT_UNICODE_NULL_BYTES = 0x1000;
public static int IS_TEXT_UNICODE_ODD_LENGTH = 0x200;
public static int IS_TEXT_UNICODE_REVERSE_ASCII16 = 0x10;
public static int IS_TEXT_UNICODE_REVERSE_CONTROLS = 0x40;
public static int IS_TEXT_UNICODE_REVERSE_MASK = 0xF0;
public static int IS_TEXT_UNICODE_REVERSE_SIGNATURE = 0x80;
public static int IS_TEXT_UNICODE_REVERSE_STATISTICS = 0x20;
public static int IS_TEXT_UNICODE_SIGNATURE = 0x8;
public static int IS_TEXT_UNICODE_STATISTICS = 0x2;
public static int IS_TEXT_UNICODE_UNICODE_MASK = 0xF;
Svo þarf að skilgreina fallið, sem er í “advapi32.dll”.
[DllImport("advapi32.dll")]
pub lic static extern int IsTextUnicode(char[] pBuffer, int cb, ref int lpi);
Þarna eru þrjár breytur sem fallið þarf að fá, í fyrsta lagi er það texti sem á að athuga, við notum char array þar sem ef við búum til strengja breytu, þá er .NET þegar búið að kóða textann í UTF-8, og það viljum við alls ekki. Næsta breyta er stærðin á pBuffer og síðasta breytan er eitthvað af IS_TEXT_UNICODE_* breytunum, auðvitað er hægt að blanda þeim saman með and og or.
Hér er svo dæmi um hvernig ég nota fallið til að lesa inn texta skrá í textabox. Þetta dæmi notar System.Text; og System.IO; í using klausunni.
FileStream fs = File.OpenRead(filename);
try
{
byte[] buffer = new byte[fs.Length];
// Lesa textann inn í byte arrayinn.
fs.Read(buffer, 0, buffer.Length);
char[] chars = new char[buffer.Length];
// Færa byte arrayinn yfir í char array
Array.Copy(buffer, chars, chars.Length);
// Skilgreina eftir hverju á að leita í textanum.
int unicodeTest = IS_TEXT_UNICODE_ILLEGAL_CHARS;
IsTextUnicode(chars, chars.Length, ref unicodeTest);
// Ef textinn inniheldur illegal chars, þá geri ég ráð fyrir
// að textinn sé kóðaður í UTF-7, annars UTF-8
if (unicodeTest == IS_TEXT_UNICODE_ILLEGAL_CHARS)
enc = Encoding.UTF7; // Betra að hafa Encoding.Default !
else
enc = Encoding.UTF8;
// Svo lesa efnið úr skránni inn í textaboxið.
textBox1.Text = enc.GetString(buffer);
}
finally
{
// Aldrei gleyma að loka filestream-um var mér einhvern tímann
// sagt, en auðvitað lokar .NET þessu fyrir mig þegar fs breytan
// er komin úr “scope”, en betra að hlýða bara ;)
fs.Close();
}
Auðvitað er þetta dæmi mitt ekki öflugt, en þetta er bara spurning um að bæta aðeins við unicodeTest breytinu og henda svo inn fleiri if skipunum ;)
Vona að einhverjir njóti góðs af.