按照MSDN,StreamWriter和StreamReader是推荐的文本文件读写类,他们会智能的处理文本格式,大可放轻松。然而,我用起来可一点都不轻松。
问题的出现在于现在这个世界的纯文本文件有太多的编码格式,ANSI、GB2312、Unicode、UTF-8....搞错了格式,打开后就是一堆乱码。
为了推广先进的编码格式,微软设置StreamReader也将不明编码的文件读为UTF-8。StreamWriter默认情况下也按UTF-8格式输出文本,而且,不带BOM(一个提示其他软件文本格式的串)。
但是,我们中文XP的默认编码格式是什么呢?好像是GB2312,反正不是UTF-8。
哦,问题出来了。我用StreamWriter输出了一个文本。再用EXCEL另存为输出了个CSV,也是文本文件。现在你猜StreamReader(使用一条语句的情况下)怎么读这两个文件?
答案是,StreamReader根本无法同时读取这两个文件(在使用一条语句的情况下)。
使用不带参数的StremReader(filename)按说明可以自动判断格式,它也确实正确读取了我用StreamWriter输出的文件。但是,他将EXCEL输出的CSV读成了乱码。
使用参数StreamReader(filename, Encoding.Default),可以正常读出EXCEL输出的CSV文件,可是,他又将我用StreamWriter输出的文件读成了乱码。
我晕死!
怎么办呢?
1、不要使用StreamWriter的默认输出,而是使用StreamWriter(filename,bool,Encoding)这个函数,这个函数将会在输出的文件前添加BOM,这样保证你的文本文件不会被误读。
2、不要依靠StreamReader的自动判断,在读取语句前增加一个判断函数,可以基本消除乱码。
下面是CSDN的孟子E章所写的判断函数(我修改了默认返回的编码)。
public static Encoding GetEncoding(string filename)
{
Encoding result = System.Text.Encoding.Default;
FileStream file = null;
try
{
file = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
if (file.CanSeek)
{
// get the bom, if there is one
byte[] bom = new byte[4];
file.Read(bom, 0, 4);
// utf-8
if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf)
result = System.Text.Encoding.UTF8;
// ucs-2le, ucs-4le, ucs-16le, utf-16, ucs-2, ucs-4
else if ((bom[0] == 0xff && bom[1] == 0xfe) ||
(bom[0] == 0xfe && bom[1] == 0xff) ||
(bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff))
result = System.Text.Encoding.Unicode;
// else ascii
else
result = System.Text.Encoding.Default;
}
else
{
// can't detect, set to default
result = System.Text.Encoding.Default;
}
return result;
}
finally
{
if (null != file) file.Close();
}
}