۱۳۸۸/۰۹/۲۰

مشكل فايل‌هاي ANSI-Windows-1256 با VS.Net در ويندوز 7


در ويندوز XP زمانيكه زبان سيستم و همچنين كشور جاري به ايران تنظيم شود، VS.Net فايل‌هاي ANSI را از نوع ANSI-Windows-1256 (يا همان ANSI-Arabic) در نظر مي‌گيرد و مشكلي هم براي ذخيره داده‌هاي يونيكد در اين نوع فايل‌هاي ANSI ويژه نخواهد بود (الزامي وجود ندارد كه اين فايل‌ها حتما به فرمت UTF8 ذخيره شوند). اما در ويندوز 7 با همان تنظيمات، VS.Net اين فايل‌ها را با encoding از نوع windows-1252 تشخيص مي‌دهد و پس از كامپايل برنامه‌اي كه قبلا مشكل نداشت، اين‌بار همه چيز به همه ريخته خواهد بود. شايد اينطور به نظر برسد كه اين فايل‌ها خراب شده‌اند، ولي خير. مشكلي وجود ندارد؛ فقط فرمت encoding خواندن آن‌ها بايد windows-1256 باشد (و نه 1252) و گرنه تخريب شده به نظر مي‌رسند.

تعداد فايل‌ها هم زياد است و نياز به يك روش سريع براي رفع اين مشكل وجود داشت.
بنابراين سه عمليات بايد صورت گيرد:
ليست كردن تمام فايل‌هاي مورد نظر (فايل‌هاي cs و aspx و امثال آن فقط)
پيدا كردن encoding جاري فايل‌ها : كداميك از آن‌ها با فرمت UTF-8 ذخيره نشده‌اند؟
تبديل به يونيكد: خواندن اين فايل‌هاي غير يونيكد يافت شده با فرمت windows-1256 و سپس ذخيره مجدد با فرمت UTF-8

كه خلاصه روش انجام كار به صورت زير است:

الف) آيا فايل جاري مورد نظر با فرمت UTF-8 with signature ذخيره شده است؟
اين signature در مورد فايل‌هاي UTF-8 به سه بايت اول فايل بر مي‌گردد كه اصطلاحا byte-order mark يا BOM گفته مي‌شود و بايد مساوي EFBBBF باشد. چون فايل‌هاي ANSI اين امضا را ندارند، در يك سيستم ممكن است 1256 خوانده شوند و در يك سيستم ديگر 1252 يا نوع‌هاي ANSI ديگر بسته به تنظيمات جاري سيستم و مشكل اصلي از VS.Net نيست.

/// <summary>
/// آيا فايل مورد نظر با فرمت يونيكد داراي امضا ذخيره شده است؟
/// </summary>
/// <param name="filePath">فايل ورودي</param>
/// <returns>بله يا خير</returns>
public static bool IsUTF8(string filePath)
{
using (FileStream file = new FileStream(filePath,
FileMode.Open, FileAccess.Read, FileShare.Read))
{
if (file.CanSeek)
{
byte[] bom = new byte[4]; // Get the byte-order mark, if there is one
file.Read(bom, 0, 4);
if ((bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf)) // utf-8
{
return true;
}
else
{
return false;
}
}
else
{
//احتمالا فايل بايناري است
return false;
}
}
}

ب) خواندن يك فايل ANSI عربي با فرمت windows-1256 بدون تخريب اطلاعات آن و سپس ذخيره سازي با فرمت UTF-8

/// <summary>
/// تبديل يك فايل انسي عربي به يونيكد داراي امضاء
/// </summary>
/// <param name="path">مسير ورودي</param>
public static void FixWindows1256(string path)
{
try
{
//باز كردن فايل با فرمت انسي عربي و تبديل به يونيكد
string data = File.ReadAllText(path, Encoding.GetEncoding("windows-1256"));
//نوشتن حاصل يونيكد در جاي قبلي با فرمت مربوطه
File.WriteAllText(path, data, Encoding.UTF8);
}
catch (Exception ex)
{
//دسترسي وجود ندارد يا امثال آن
Console.WriteLine(ex.ToString());
}
}


پ.ن.
جالب اينجا است كه اين نوع فايل‌هاي ANSI عربي در وب زياد پيدا مي‌شوند. براي مثال اينجا كليك كنيد. تمام اين نوع فايل‌ها را با متد فوق مي‌توان بدون تخريب اطلاعات به فرمت UTF-8 داراي امضاء اصلاح كرد.