Есть ли лучший способ конвертировать в ASCII с произвольного ввода?

StackOverflow https://stackoverflow.com/questions/309734

  •  08-07-2019
  •  | 
  •  

Вопрос

Мне нужно иметь возможность взять произвольный текстовый ввод, который может иметь маркер порядка байтов (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())

Это должно сэкономить несколько поездок туда и обратно.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top