Silverlight读取包含中文的txt(解决乱码问题)
虽然Silverlight已经是被抛弃的孩子了,但此前做的一些项目还是用到Silverlight。今天用Silverlight导入客户端本地的一个txt文件,然后读取需要的信息。随手记录一下,留作以后备忘。
网上也有不少的相关资料,但好像要么是单纯的Ctrl+C、Ctrl+V,要么是不够齐全。闲话少说,直接上代码。
我用的是MVVM模式,所以用RelayCommand命令打开了。其它的,直接在类似Button_Click事件里调用OpenFile(),同理。
1 /// <summary> 2 /// 打开文件 3 /// </summary> 4 private void OpenFile() 5 { 6 try 7 { 8 //检查是否是在OOB模式下运行 9 OOBChecker.CheckInstallState(() => 10 { 11 //弹出选择文件对话框 12 OpenFileDialog fileDialog = new OpenFileDialog() 13 { 14 Filter = "Txt Files (*.txt)|*.txt|All Files (*.*)|*.*", 15 }; 16 17 if (fileDialog.ShowDialog() == true) 18 { 19 //读取文件流 20 using (Stream fs = fileDialog.File.OpenRead()) 21 { 22 ReadTxtFile(fs); 23 fs.Close(); 24 } 25 } 26 }); 27 } 28 catch (Exception e) 29 { 30 31 //错误处理 32 } 33 }
注: OOBChecker.CheckInstallState,是为公司项目需要写的一个检查Silverlight程序是否在浏览器外运行的方法。众所周知,Silverlight是可以安装在本机脱离浏览器运行的,这样便可获得更高的执行权限。有时对本地文件(夹)进行操作时,程序需要获得信任权限。不知是否我浏览器设置问题,我直接在IE上运行,貌似也有权限。
附上OOBChecker的代码。
public class OOBChecker { /// <summary> /// 当前程序是否安装在本地 /// </summary> private static bool IsInstall { get; set; } /// <summary> /// 检查当前程序有没有安装在本地,callback是回调 /// </summary> public static void CheckInstallState(Action callback) { try { if (App.Current.HasElevatedPermissions) { //跳过OOB验证,直接在网页打开 if (callback != null) { callback(); return; } } if (App.Current.InstallState == InstallState.Installed) { if (App.Current.IsRunningOutOfBrowser) { IsInstall = true; //项目中操作Office COM需要 if (AutomationFactory.IsAvailable) { if (callback != null) { callback(); } } else { MessageWindow.CreateNew("您好,AutomationFactory IsAvailable Is False", resTipInformation.strApplicationTitle); } //App.Current.MainWindow.TopMost = true; } else { MessageWindow.CreateNew("您好,您已在本机安装了模块程序,请保存本页面数据后双击运行桌面的图标。", resTipInformation.strApplicationTitle); } } else { MessageWindow.CreateNewConfirm("打开文档之前需要安装本程序在您电脑上,确定帮您安装吗?为避免数据丢失,请确认前先保存数据。", resTipInformation.strApplicationTitle, () => { App.Current.InstallStateChanged += Current_InstallStateChanged; App.Current.Install(); }); } } catch (Exception ex) { ErrorWindow.CreateNew(ex); Debug.WriteLine(string.Format("{0} at {1}", ex.Message, "OOBChecker")); } } /// <summary> /// 安装完成后 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void Current_InstallStateChanged(object sender, System.EventArgs e) { if (App.Current.InstallState == InstallState.Installed) { IsInstall = true; } } }
OpenFile方法中,调用了一个读取文件内容的方法:ReadTxtFile
1 /// <summary> 2 /// 一行行地循环读取 3 /// </summary> 4 private void ReadTxtFile(Stream fs) 5 { 6 var myTable = new List<string>(); 7 using (StreamReader reader = new StreamReader(fs, new Gb2312Encoding())) 8 { 9 /* 10 * 一次性读出所有文件信息 11 * var fileText = string.Empty; 12 fileText = reader.ReadToEnd(); 13 */ 14 15 reader.BaseStream.Seek(0, SeekOrigin.Begin); 16 string strLine = reader.ReadLine(); 17 var tableIndex = 0; 18 while (strLine != null) 19 { 20 /* 21 * do your things here 22 if (strLine.Contains("[Your message is here]")) 23 { 24 //找到表头了 25 tableIndex++; 26 } 27 28 if (tableIndex > 6) 29 { 30 //读完需要的表信息了,跳出 31 break; 32 } 33 34 if (tableIndex >= 4) 35 { 36 //开始获取需要的信息 37 myTable.Add(strLine); 38 } 39 if (tableIndex > 0) 40 { 41 tableIndex++; 42 } 43 */ 44 strLine = reader.ReadLine(); 45 } 46 reader.Close(); 47 } 48 49 if (myTable.Any()) 50 { 51 foreach (var strItem in myTable) 52 { 53 var view = strItem.TrimEnd('\t').Split('\t'); 54 //do something here 55 } 56 } 57 58 }
注:Silverlight不支持GB2312编码,所以打开中文时会乱码。为此,我们可以继承Encoding,自己为程序添加GB2312编码。然后像下面那样调用。
StreamReader reader = new StreamReader(fs, new Gb2312Encoding())
Gb2312Encoding的代码,里面包含了个Gb2312toUnicodeDictinary(这个是网上找的,很多网上资料只有Gb2312Encoding,却没有附上Gb2312toUnicodeDictinary)。
只上Gb2312Encoding的代码吧,Gb2312toUnicodeDictinary有7000多行的说……,这两个文件以附件形式放在后面,有需要的童鞋自行下载。
1 public class Gb2312Encoding : Encoding 2 { 3 public override string WebName 4 { 5 get 6 { 7 return "gb2312"; 8 } 9 } 10 11 public Gb2312Encoding() 12 { 13 14 } 15 public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) 16 { 17 throw new NotImplementedException(); 18 } 19 20 public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) 21 { 22 int j = 0; 23 char c; 24 for (int i = 0; i < byteCount; i += 2) 25 { 26 if (i + 1 >= bytes.Length) 27 { 28 char[] last = Encoding.UTF8.GetChars(new byte[] { bytes[i] }); 29 chars[j] = last[0]; 30 } 31 else 32 { 33 byte[] bb = new byte[] { bytes[i], bytes[i + 1] }; 34 if (Gb2312toUnicodeDictinary.TryGetChar(bb, out c)) 35 { 36 chars[j] = c; 37 j++; 38 } 39 else 40 { 41 char[] tt = Encoding.UTF8.GetChars(new byte[] { bb[1] }); 42 chars[j] = tt[0]; 43 j++; 44 //测试下一个 45 if (i + 2 >= bytes.Length) 46 { 47 char[] tttt = Encoding.UTF8.GetChars(new byte[] { bb[0] }); 48 chars[j] = tttt[0]; 49 j++; 50 } 51 else 52 { 53 byte[] test = new byte[] { bb[0], bytes[i + 2] }; 54 if (Gb2312toUnicodeDictinary.TryGetChar(test, out c)) 55 { 56 chars[j] = c; 57 j++; 58 i++; 59 } 60 else 61 { 62 char[] ttt = Encoding.UTF8.GetChars(new byte[] { bb[0] }); 63 chars[j] = ttt[0]; 64 j++; 65 } 66 67 } 68 } 69 } 70 } 71 72 return chars.Length; 73 } 74 75 public override int GetByteCount(char[] chars, int index, int count) 76 { 77 return count; 78 } 79 public override int GetCharCount(byte[] bytes, int index, int count) 80 { 81 return count; 82 } 83 84 public override int GetMaxByteCount(int charCount) 85 { 86 return charCount; 87 } 88 public override int GetMaxCharCount(int byteCount) 89 { 90 return byteCount; 91 } 92 public static int CharacterCount 93 { 94 get { return 7426; } 95 } 96 }
作者:Ivan