继this question之前,我有一个补充问题。
我找到了标题中带有“É”的曲目。
我的代码:
var playList = new StreamWriter(playlist, false, Encoding.UTF8);
-
private static void WriteUTF8(StreamWriter playList, string output)
{
byte[] byteArray = Encoding.UTF8.GetBytes(output);
foreach (byte b in byteArray)
{
playList.Write(Convert.ToChar(b));
}
}
将其转换为以下字节:
195
137
输出为Ã后跟一个正方形(这是一个无法用当前字体打印的字符)。
我已经将相同的文件导出到Media Monkey中的播放列表,因为它将“É”写为“É” - 我认为这是正确的(正如KennyTM指出的那样)。
我的问题是,如何获得“‰”符号输出?我是否需要选择不同的字体,如果是这样的话?
更新
人们似乎忽视了这一点。
我可以使用
将“É”写入文件playList.WriteLine("É");
这不是问题。
问题是Media Monkey要求文件采用以下格式:
#EXTINFUTF8:140,Yann Tiersen - Comptine D'Un Autre Été: L'Après Midi
#EXTINF:140,Yann Tiersen - Comptine D'Un Autre Été: L'Après Midi
#UTF8:04-Comptine D'Un Autre Été- L'Après Midi.mp3
04-Comptine D'Un Autre Été- L'Après Midi.mp3
所有“高ascii”(为了更好的术语)都写成一对字符。
更新2
我应该将c9
替换为c3 89
。
我打算把我实际得到的东西,但在为此进行测试时,我设法得到一个测试程序,以“按原样”输出正确格式的文本。所以我需要做更多的调查。
答案 0 :(得分:3)
这样使用Convert.ToChar
几乎肯定是一个坏主意。你基本上编码了两次。
您应该 自己执行转换,然后直接写入流或,您应该让StreamWriter
进行转换。如果您尝试自己执行转换,为什么还要使用StreamWriter
?
您是要写入二进制文件还是简单的文本文件?如果它是一个简单的文本文件,只需使用StreamWriter
并让它进行转换。如果它是二进制文件,请使用Stream
而不是StreamWriter
,并在需要的地方直接执行文本编码,然后将字节直接写入流中。
编辑:以下是原始代码的内容:
Encoding.UTF8.GetBytes(text) => byte[] { 0xc3, 0x89 };
Convert.ToChar(0xc3) => char U+00C3
StreamWriter writes U+00C3 as byte[] { 0xc3, 0x83 };
Convert.ToChar(0x89) => char U+0089
StreamWriter writes U+00C3 as byte[] { 0xc2, 0x89 };
这就是为什么你要把c3 83 c2 89写入文件。
答案 1 :(得分:2)
我不做C#但症状告诉我你确实把它写成了UTF-8,但输出/控制台/应用程序/你正在查看的任何东西写入输出不是使用UTF-8,而是使用ISO-8859-1来显示它们,而MediaMonkey正在使用CP1252来显示它们。
如果您在IDE控制台中查看它们,则需要将IDE配置为使用UTF-8
作为控制台和文本文件编码。
更新您显然希望将UTF-8
数据写为CP-1252
。现在问题/问题更清楚了。同样,我不做C#,但Java等价物是:
Writer writer = new OutputStreamWriter(new FileOutputStream("file.ext"), "CP-1252");
writer.write(someUTF8String); // Will be written as CP-1252. "É" would become "É"
希望这能提供一些见解。
答案 2 :(得分:2)
StreamWriter
已经将您发送的字符转换为UTF-8 - 这就是它的全部目的。扔掉WriteUTF8
;它破碎无用。
(WriteUTF8
正在取字符,将它们转换为UTF-8字节,将每个字节转换为它在当前代码页中映射到的字符,然后对每个那些字符进行编码在UTF-8中。所以在最好的情况下你有一个双重UTF-8编码的字符串;在最坏的情况下,你已经完全丢失了未在系统代码页库中映射的字节;特别是对于DBCS代码页不好。)
您使用Media Monkey遇到的问题可能只是它根本不支持UTF-8或Unicode文件名。尝试让它播放(并导出播放列表)文件,其中包含不适合您系统代码页的字符,例如将文件重命名为αβγ.mp3
。
编辑:
#EXTINFUTF8:140,Yann Tiersen - Comptine D'Un Autre Été: L'Après Midi
#EXTINF:140,Yann Tiersen - Comptine D'Un Autre Été: L'Après Midi
#UTF8:04-Comptine D'Un Autre Été- L'Après Midi.mp3
04-Comptine D'Un Autre Été- L'Après Midi.mp3
好的,你在那里得到的是同一文件中的混合编码:难怪文本编辑器在打开它时会遇到麻烦。未注释和#EXTINF
行位于系统默认代码页中,用于支持无法读取Unicode文件名的媒体播放器。系统代码页中不存在的任何文件名字符(例如,上面的希腊语,在西方Windows上安装)将被修改,并且对于任何不了解#UTF8
(和#EXTINFUTF8
的任何内容都无法播放线条。
因此,如果这是您的目标格式,您需要抓取两个编码并依次使用每个编码,例如:
private static void writePlaylistEntry(Stream playlist, string filename, int length) {
Encoding utf8= new UTF8Encoding(false);
Encoding ansi= Encoding.Default;
playlist.Write(utf8.GetBytes("#EXTINFUTF8:"+length+","+filename+"\n"));
playlist.Write(ansi.GetBytes("#EXTINF:"+length+","+filename+"\n"));
playlist.Write(utf8.GetBytes("#UTF8:"+filename+"\n"));
playlist.Write(ansi.GetBytes(filename+"\n"));
}
答案 3 :(得分:2)
方法名称中更基本的问题是:
private static void WriteUTF8(...)
.M3U文件不是UTF-8。他们是Latin-1(或Windows-1252)。
而不是Encoding.UTF8
,您应该使用Encoding.GetEncoding(1252)
。然后你可以直接写入流,你不需要任何这种转换怪异。
<强>更新强>
我刚尝试了以下C#代码,结果.M3U在Winamp和WMP中都很好用:
static void Main(string[] args)
{
string fileName = @"C:\Temp\Test.m3u";
using (StreamWriter writer = new StreamWriter(fileName, false,
Encoding.GetEncoding(1252)))
{
writer.WriteLine("#EXTM3U");
writer.WriteLine("#EXTINF:140,Yann Tiersen " +
"- Comptine D'Un Autre Été: L'Après Midi");
writer.WriteLine("04-Comptine D'Un Autre Été- L'Après Midi.mp3");
}
}
所以,正如我所说 - 只需使用正确的编码即可。您不需要所有额外的#EXTINFUTF8
和#UTF8
行,除非它对Media Monkey有一些奇怪的要求(它绝对不是基本M3U规范的一部分)。
答案 4 :(得分:0)
对,首先感谢大家的帮助和耐心。
我终于让它正常工作了。我已经实现了bobince解决方案的一个版本,这就是为什么他得到了接受(向所有其他人投票)。这是我的代码:
var playList = new StreamWriter(playlist, false, Encoding.Default);
playList.WriteLine("#EXTM3U");
foreach (string track in tracks)
{
// Read ID3 tags from file
var info = new FileProperties(track);
// Write extended info (#EXTINF:<time>,<artist> - <title>
if (Encoding.UTF8.GetBytes(info.Artist).Length != info.Artist.Length ||
Encoding.UTF8.GetBytes(info.Title).Length != info.Title.Length)
{
playList.Close();
playList = new StreamWriter(playlist, true, Encoding.UTF8);
playList.WriteLine(string.Format("#EXTINFUTF8:{0},{1} - {2}",
info.Duration, info.Artist, info.Title));
playList.Close();
playList = new StreamWriter(playlist, true, Encoding.Default);
}
playList.WriteLine(string.Format("#EXTINF:{0},{1} - {2}",
info.Duration, info.Artist, info.Title));
// Write the name of the file (removing the drive letter)
string file = Path.GetFileName(track);
if (Encoding.UTF8.GetBytes(file).Length != file.Length)
{
playList.Close();
playList = new StreamWriter(playlist, true, Encoding.UTF8);
playList.WriteLine(string.Format("#UTF8:{0}", file));
playList.Close();
playList = new StreamWriter(playlist, true, Encoding.Default);
}
playList.WriteLine(file);
}
playList.Close();
正如您所看到的,我假设我不必编写UTF8,但是当我这样做时,我关闭流并使用UTF8编码重新打开它。然后,在写完违规行之后,关闭并使用默认编码重新打开它。
现在我不知道为什么我之前的代码给出了不一致的结果。鉴于每个人(特别是乔恩)所说的应该一直失败,或者可能一直都在工作。