C#自动识别文件编码

时间:2021-08-10 06:02:28

在做导入微信商户后台退款数据时,无论怎么设置编码导出来都是乱码,后来在网上找了这个识别文件编码的代码,感觉不错。

C#自动识别文件编码最后识别出来是gb2312,看来我还是太渣了,只能吃土了,竟然忘记了这个编码。

 

下面,上代码。

  1 /// <summary>   
2 /// 用于取得一个文本文件的编码方式(Encoding)。
3 /// </summary>
4 public class TxtFileEncoder
5 {
6 public TxtFileEncoder()
7 {
8 //
9 // TODO: 在此处添加构造函数逻辑
10 //
11 }
12 /// <summary>
13 /// 取得一个文本文件的编码方式。如果无法在文件头部找到有效的前导符,Encoding.Default将被返回。
14 /// </summary>
15 /// <param name="fileName">文件名。</param>
16 /// <returns></returns>
17 public static Encoding GetEncoding(string fileName)
18 {
19 return GetEncoding(fileName, Encoding.Default);
20 }
21 /// <summary>
22 /// 取得一个文本文件流的编码方式。
23 /// </summary>
24 /// <param name="stream">文本文件流。</param>
25 /// <returns></returns>
26 public static Encoding GetEncoding(FileStream stream)
27 {
28 return GetEncoding(stream, Encoding.Default);
29 }
30 /// <summary>
31 /// 取得一个文本文件的编码方式。
32 /// </summary>
33 /// <param name="fileName">文件名。</param>
34 /// <param name="defaultEncoding">默认编码方式。当该方法无法从文件的头部取得有效的前导符时,将返回该编码方式。</param>
35 /// <returns></returns>
36 public static Encoding GetEncoding(string fileName, Encoding defaultEncoding)
37 {
38 FileStream fs = new FileStream(fileName, FileMode.Open);
39 Encoding targetEncoding = GetEncoding(fs, defaultEncoding);
40 fs.Close();
41 return targetEncoding;
42 }
43 /// <summary>
44 /// 取得一个文本文件流的编码方式。
45 /// </summary>
46 /// <param name="stream">文本文件流。</param>
47 /// <param name="defaultEncoding">默认编码方式。当该方法无法从文件的头部取得有效的前导符时,将返回该编码方式。</param>
48 /// <returns></returns>
49 public static Encoding GetEncoding(FileStream stream, Encoding defaultEncoding)
50 {
51 Encoding targetEncoding = defaultEncoding;
52 if (stream != null && stream.Length >= 2)
53 {
54 //保存文件流的前4个字节
55 byte byte1 = 0;
56 byte byte2 = 0;
57 byte byte3 = 0;
58 byte byte4 = 0;
59 //保存当前Seek位置
60 long origPos = stream.Seek(0, SeekOrigin.Begin);
61 stream.Seek(0, SeekOrigin.Begin);
62
63 int nByte = stream.ReadByte();
64 byte1 = Convert.ToByte(nByte);
65 byte2 = Convert.ToByte(stream.ReadByte());
66 if (stream.Length >= 3)
67 {
68 byte3 = Convert.ToByte(stream.ReadByte());
69 }
70 if (stream.Length >= 4)
71 {
72 byte4 = Convert.ToByte(stream.ReadByte());
73 }
74 //根据文件流的前4个字节判断Encoding
75 //Unicode {0xFF, 0xFE};
76 //BE-Unicode {0xFE, 0xFF};
77 //UTF8 = {0xEF, 0xBB, 0xBF};
78 if (byte1 == 0xFE && byte2 == 0xFF)//UnicodeBe
79 {
80 targetEncoding = Encoding.BigEndianUnicode;
81 }
82 if (byte1 == 0xFF && byte2 == 0xFE && byte3 != 0xFF)//Unicode
83 {
84 targetEncoding = Encoding.Unicode;
85 }
86 if (byte1 == 0xEF && byte2 == 0xBB && byte3 == 0xBF)//UTF8
87 {
88 targetEncoding = Encoding.UTF8;
89 }
90 //恢复Seek位置
91 stream.Seek(origPos, SeekOrigin.Begin);
92 }
93 return targetEncoding;
94 }
95
96
97
98 // 新增加一个方法,解决了不带BOM的 UTF8 编码问题
99
100 /// <summary>
101 /// 通过给定的文件流,判断文件的编码类型
102 /// </summary>
103 /// <param name="fs">文件流</param>
104 /// <returns>文件的编码类型</returns>
105 public static System.Text.Encoding GetEncoding(Stream fs)
106 {
107 byte[] Unicode = new byte[] { 0xFF, 0xFE, 0x41 };
108 byte[] UnicodeBIG = new byte[] { 0xFE, 0xFF, 0x00 };
109 byte[] UTF8 = new byte[] { 0xEF, 0xBB, 0xBF }; //带BOM
110 Encoding reVal = Encoding.Default;
111
112 BinaryReader r = new BinaryReader(fs, System.Text.Encoding.Default);
113 byte[] ss = r.ReadBytes(4);
114 if (ss[0] == 0xFE && ss[1] == 0xFF && ss[2] == 0x00)
115 {
116 reVal = Encoding.BigEndianUnicode;
117 }
118 else if (ss[0] == 0xFF && ss[1] == 0xFE && ss[2] == 0x41)
119 {
120 reVal = Encoding.Unicode;
121 }
122 else
123 {
124 if (ss[0] == 0xEF && ss[1] == 0xBB && ss[2] == 0xBF)
125 {
126 reVal = Encoding.UTF8;
127 }
128 else
129 {
130 int i;
131 int.TryParse(fs.Length.ToString(), out i);
132 ss = r.ReadBytes(i);
133
134 if (IsUTF8Bytes(ss))
135 reVal = Encoding.UTF8;
136 }
137 }
138 r.Close();
139 return reVal;
140
141 }
142
143 /// <summary>
144 /// 判断是否是不带 BOM 的 UTF8 格式
145 /// </summary>
146 /// <param name="data"></param>
147 /// <returns></returns>
148 private static bool IsUTF8Bytes(byte[] data)
149 {
150 int charByteCounter = 1;  //计算当前正分析的字符应还有的字节数
151 byte curByte; //当前分析的字节.
152 for (int i = 0; i < data.Length; i++)
153 {
154 curByte = data[i];
155 if (charByteCounter == 1)
156 {
157 if (curByte >= 0x80)
158 {
159 //判断当前
160 while (((curByte <<= 1) & 0x80) != 0)
161 {
162 charByteCounter++;
163 }
164 //标记位首位若为非0 则至少以2个1开始 如:110XXXXX...........1111110X 
165 if (charByteCounter == 1 || charByteCounter > 6)
166 {
167 return false;
168 }
169 }
170 }
171 else
172 {
173 //若是UTF-8 此时第一位必须为1
174 if ((curByte & 0xC0) != 0x80)
175 {
176 return false;
177 }
178 charByteCounter--;
179 }
180 }
181 if (charByteCounter > 1)
182 {
183 throw new Exception("非预期的byte格式!");
184 }
185 return true;
186 }
187 }