c# 读txt出现乱码的处理方式

用System.IO.StreamReader读取包含汉字的txt文件时,经常会读出乱码(StreamWriater写文本文件也有类似的问题),原因很简单,就是文件的编码(encoding)和StreamReader/Writer的encoding不对应。为了解决这个问题,我写了一个类,来取得一个文本文件的encoding,这样我们就可以创建对应的StreamReader和StreamWrite来读写,保证不会出现乱码现象。其实原理很简单,文本编辑器(比如XP自带的记事本)在生成文本文件时,如果编码格式和系统默认的编码(中文系统下默认为GB2312)不一致时,会在txt文件开头部分添加特定的“编码字节序标识(Encoding Bit Order Madk,简写为BOM)”,类似PE格式的"MZ"文件头。这样它在读取时就可以根据这个BOM来确定该文本文件生成时所使用的Encoding。这个BOM我们用记事本等程序打开默认是看不到的,但是用stream按字节读取时是可以读到的。我的这个TxtFileEncoding类就是根据这个BOM“文件头”来确定txt文件生成时用到的编码的。
 1 /// <summary>
 2     /// 获取文本文件的编码方式
 3     /// </summary>
 4     class TxtFileEncoding
 5     {
 6         public TxtFileEncoding(){}
 7 
 8         /// <summary>
 9         /// 获取文本文件的编码方式
10         /// </summary>
11         /// <param name="fileName"> 文件名 例如:path = @"D:\test.txt"</param>
12         /// <returns>返回编码方式</returns>
13         public static Encoding GetEncoding(string fileName )
14         {
15             return GetEncoding(fileName, Encoding.Default);
16         }
17 
18         /// <summary>
19         /// 获取文本流的编码方式
20         /// </summary>
21         /// <param name="fs">文本流</param>
22         /// <returns>返回系统默认的编码方式</returns>
23         public static Encoding GetEncoding(FileStream fs)
24         {
25             //Encoding.Default 系统默认的编码方式
26             return GetEncoding(fs, Encoding.Default);
27         }
28 
29         /// <summary>
30         /// 获取一个文本流的编码方式
31         /// </summary>
32         /// <param name="fileName">文件名</param>
33         /// <param name="defaultEncoding">默认编码方式。当该方法无法从文件的头部取得有效的前导符时,将返回该编码方式。</param>
34         /// <returns></returns>
35         public static Encoding GetEncoding(string fileName, Encoding defaultEncoding)
36         {
37             FileStream fs = File.Open(fileName,FileMode.Open);
38             Encoding targetEncoding = GetEncoding(fs, defaultEncoding);
39             fs.Close();
40             return targetEncoding;
41         }
42 
43         /// <summary>
44         /// 获取一个文本流的编码方式
45         /// </summary>
46         /// <param name="fs">文本流</param>
47         /// <param name="defaultEncoding">默认编码方式。当该方法无法从文件的头部取得有效的前导符时,将返回该编码方式。</param>
48         /// <returns></returns>
49         public static Encoding GetEncoding(FileStream fs, Encoding defaultEncoding)
50         {
51             Encoding targetEncoding = defaultEncoding;
52             if (fs != null && fs.Length >= 2)
53             {
54                 byte b1 = 0;
55                 byte b2 = 0;
56                 byte b3 = 0;
57                 byte b4 = 0;
58 
59                 long oriPos = fs.Seek(0, SeekOrigin.Begin);
60                 fs.Seek(0, SeekOrigin.Begin);
61 
62                 b1 = Convert.ToByte(fs.ReadByte());
63                 b2 = Convert.ToByte(fs.ReadByte());
64                 if (fs.Length > 2)
65                 {
66                     b3 = Convert.ToByte(fs.ReadByte());
67                 }
68                 if (fs.Length > 3)
69                 {
70                     b4 = Convert.ToByte(fs.ReadByte());
71                 }
72 
73                 //根据文件流的前4个字节判断Encoding
74                 //Unicode {0xFF, 0xFE};
75                 //BE-Unicode {0xFE, 0xFF};
76                 //UTF8 = {0xEF, 0xBB, 0xBF};
77                 if (b1 == 0xFE && b2 == 0xFF)//UnicodeBe
78                 {
79                     targetEncoding = Encoding.BigEndianUnicode;
80                 }
81                 if (b1 == 0xFF && b2 == 0xFE && b3 != 0xFF)//Unicode
82                 {
83                     targetEncoding = Encoding.Unicode;
84                 }
85                 if (b1 == 0xEF && b2 == 0xBB && b3 == 0xBF)//UTF8
86                 {
87                     targetEncoding = Encoding.UTF8;
88                 }
89 
90                 fs.Seek(0, SeekOrigin.Begin);
91             }
92             fs.Close();
93             return targetEncoding;
94         }
95     }

 

 

posted @ 2015-10-26 10:17  wasim  阅读(2985)  评论(0编辑  收藏  举报