Есть ли лучший способ конвертировать в ASCII с произвольного ввода?
Вопрос
Мне нужно иметь возможность взять произвольный текстовый ввод, который может иметь маркер порядка байтов (BOM), чтобы пометить его кодировку, и вывести его как ASCII. У нас есть несколько старых инструментов, которые не понимают спецификации, и мне нужно отправлять им данные только для ASCII.
Теперь, я только что закончил написание этого кода, и я просто не могу поверить в неэффективность здесь. Четыре копии данных, не говоря уже о каких-либо промежуточных буферах внутри StreamReader. Есть ли лучший способ сделать это?
// i_fileBytes is an incoming byte[]
string unicodeString = new StreamReader(new MemoryStream(i_fileBytes)).ReadToEnd();
byte[] unicodeBytes = Encoding.Unicode.GetBytes(unicodeString.ToCharArray());
byte[] ansiBytes = Encoding.Convert(Encoding.Unicode, Encoding.ASCII, unicodeBytes);
string ansiString = Encoding.ASCII.GetString(ansiBytes);
Мне нужен StreamReader (), потому что у него есть внутренний детектор спецификации для выбора кодировки для чтения остальной части файла. Тогда остальное - просто преобразовать его в окончательную строку ASCII.
Есть ли лучший способ сделать это?
Решение
Если у вас уже есть i_fileBytes в памяти, вы можете просто проверить, начинается ли он с спецификации, а затем преобразовать либо всю ее, либо только бит после спецификации, используя Encoding.Unicode.GetString код>. (Используйте перегрузку, которая позволяет указывать индекс и длину.)
Так как код:
int start = (i_fileBytes[0] == 0xff && i_fileBytes[1] == 0xfe) ? 2 : 0;
string text = Encoding.Unicode.GetString(i_fileBytes, start, i_fileBytes.Length-start);
Обратите внимание, что здесь подразумевается действительно кодировка UTF-16 с прямым порядком байтов. Если вам действительно нужно сначала определить кодировку, вы можете либо переопределить то, что делает StreamReader, либо, возможно, просто построить StreamReader из первых (скажем) 10 байтов и использовать свойство CurrentEncoding, чтобы выяснить, что вам следует использовать для кодирования.
РЕДАКТИРОВАТЬ: Теперь, что касается преобразования в ASCII - если вам действительно нужно это только как строку .NET, тогда, вероятно, все, что вы хотите сделать, - это заменить любые не-ASCII-символы на "? " или что-то подобное. (В качестве альтернативы может быть лучше создать исключение ... это, конечно, зависит от вас.)
РЕДАКТИРОВАТЬ: обратите внимание, что при обнаружении кодирования было бы неплохо просто вызвать Read ()
один раз, чтобы прочитать один символ. Не вызывайте ReadToEnd ()
, так как при выборе 10 байтов в качестве произвольного объема данных он может заканчиваться средним символом. Я не знаю, будет ли это исключение, но в любом случае это не принесет пользы ...
Другие советы
System.Text.Encoding.ASCII.GetBytes(new StreamReader(new MemoryStream(i_fileBytes)).ReadToEnd())
Это должно сэкономить несколько поездок туда и обратно.