:: Не фоксом единым
Переввести в 16-ричный вид
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Есть небольшой файл ttt.txt следующего содержимого:

это текст в кодировке win1251

В 16-ричном виде это выглядит как:

[attachment 25858 s1.png]

Как на C# преобразовать текст файла в 16-ричный вид?
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Попробовал так:

// читаем файл
StreamReader txtFile1 = new StreamReader(@"c:\temp\ttt.txt");
string ddd = txtFile1.ReadToEnd();
txtFile1.Close();
// Преобразуем
txtBoxRespons.Text = PrintHexBytes(ddd);
[...]
// функция слегка переделанная с [url]https://msdn.microsoft.com/ru-ru/library/bb311038.aspx[/url]
public string PrintHexBytes(string input)
{
StringBuilder hexOutpu = new StringBuilder();
char[] values = input.ToCharArray();
foreach (char letter in values)
{
int value = Convert.ToInt32(letter);
hexOutpu.Append(String.Format("{0:X} ", value));
}
return hexOutpu.ToString();
}

В итоге вижу:

[attachment 25859 s2.png]
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Подозреваю (возможно и не прав), что проблема в:

char[] values = input.ToCharArray();

Господа, помогите!
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Попытался сделать через byte - не получилось:

public string PrintHexBytes(string input)
{
byte[] bytes = Encoding.Win1251.GetBytes(input); // так нельзя !
StringBuilder hexOutput =new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
hexOutput.Append(String.Format("{0:X2} ", bytes[i]));
}
return hexOutput.ToString();
}
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Ура, получилось.

StreamReader txtFile1 = new StreamReader(@"c:\temp\ttt.txt", Encoding.GetEncoding(1251)); // тут надо было указывать!
string ddd = txtFile1.ReadToEnd();
txtFile1.Close();
txtBoxRespons.Text = PrintHexBytes(ddd);
[...]
public string PrintHexBytes(string input)
{
byte[] bytes = Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding("windows-1251"), Encoding.UTF8.GetBytes(input));
StringBuilder hexOutput = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
hexOutput.Append(String.Format("{0:X2} ", bytes[i]));
}
return hexOutput.ToString();
}
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
ssa

Сообщений: 13007
Откуда: Москва
Дата регистрации: 23.03.2005
М-да... Перевод чисел из одной системы счисления в другую вроде как всегда был чуть ли не первым домашним заданием начинающим программистам...


------------------
Лень - это неосознанная мудрость.
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
В C# строки (и символы, которые char) юникодные. Если в файле текст в нужной кодировке (в той, hex коды символов которой и нужно получать) то нужно банально НЕ читать его в "строку" - в "байты" и читай сразу - а их уж, если надо, и переводи в hex символы (опять же вопрос - ну на консоль, понятно - там "напечатало и напечатало", а если это нужно в какой файл кидать - то в какой кодировке? )


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Igor Korolyov
Если в файле текст в нужной кодировке (в той, hex коды символов которой и нужно получать) то нужно банально НЕ читать его в "строку" - в "байты" и читай сразу - а их уж, если надо, и переводи в hex символы

Вы предлагаете использовать BinaryReader?
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Проверил:

StreamReader txtFile1 = new StreamReader(@"c:\temp\ttt.txt");
BinaryReader binFile1 = new BinaryReader(txtFile1.BaseStream);
byte[] bytes1 = new byte[1000];
int count=binFile1.Read(bytes1, 0, 1000);
txtFile1.Close();
txtBoxRespons.Text = PrintHexBytes(bytes1, count);
[...]
public string PrintHexBytes(byte[] bytes,int count)
{
StringBuilder hexOutput = new StringBuilder();
for (int i = 0; i < count; i++)
{
hexOutput.Append(String.Format("{0:X2} ", bytes[i]));
}
return hexOutput.ToString();
}

Так то же работает! Спасибо.
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Анализ разных вариантов и выбор наиболее быстрого. В части конвертации byte[] в string содержащий hex-значения этих байт, и обратно.
stackoverflow.com


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Честно говоря, не понял мысли. По ссылке первый же пример:

public static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}

очень похоже на PrintHexBytes.
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Третий пост - Performance Analysis.
Здоровенный список различных вариантов и их сравнительная скорость.
Твой начальный вариант, я полагаю, будет ЕЩЁ медленнее, т.к. ты не задаёшь размер буфера для StringBuilder, а это будет приводить к его ресайзам. Но и ближайший аналог с foreach и StringBuilder.AppendFormat в тесте занимает предпоследнее место - он всего в 1.1 раза быстрее самого медленного из протестированных вариантов. Тогда как лидер в 100 раз быстрее (но там unsafe код используется) а "почётное второе место" (та же идея но без unsafe кода) в 43-45 раз быстрее.
Вот в этом, собственно говоря, и была мысль


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Igor Korolyov
Если в файле текст в нужной кодировке (в той, hex коды символов которой и нужно получать) то нужно банально НЕ читать его в "строку" - в "байты" и читай сразу - а их уж, если надо, и переводи в hex символы
Вот код - читаю побайтно сразу в нужной кодировке. Ни каких дополнительных массивов и ни каких дополнительных перекодировок.

StreamReader txtFile1 = new StreamReader(@"c:\temp\ttt.txt");
BinaryReader binFile1 = new BinaryReader(txtFile1.BaseStream);
StringBuilder hexOutput = new StringBuilder();
for (int i = 0; i < txtFile1.BaseStream.Length; i++)
{
hexOutput.Append($"{binFile1.ReadByte():X2} ");
}
txtFile1.Close();
txtBoxRespons.Text = hexOutput.ToString();



Исправлено 1 раз(а). Последнее : S-type, 18.09.16 22:41
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Igor Korolyov
Третий пост - Performance Analysis.
т.к. ты не задаёшь размер буфера для StringBuilder, а это будет приводить к его ресайзам.

Неужели, если в предыдущем примере

StringBuilder hexOutput = new StringBuilder();


заменить на

StringBuilder hexOutput = new StringBuilder((int)txtFile1.BaseStream.Length*2);

станет работать быстрее?
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Предположим, есть такой код:

#region Неизменяемая часть
StreamReader txtFile1 = new StreamReader(@"c:\temp\ttt.txt");
BinaryReader binFile1 = new BinaryReader(txtFile1.BaseStream);
byte[] bytes1 = new byte[txtFile1.BaseStream.Length];
int count = binFile1.Read(bytes1, 0, (int)txtFile1.BaseStream.Length);
txtFile1.Close();
#endregion
txtBoxRespons.Text = PrintHexBytes(bytes1);
[...]
public string PrintHexBytes(byte[] bytes)
{
return BitConverter.ToString(bytes).Replace("-", " ");
}

Да, если его заменить на:

Неизменяемая часть
txtBoxRespons.Text = ByteArrayToHexViaLookup32(bytes1);
[...]
private static readonly uint[] _lookup32 = CreateLookup32();
private static uint[] CreateLookup32()
{
var result = new uint[256];
for (int i = 0; i < 256; i++)
{
string s = i.ToString("X2");
result[i] = ((uint)s[0]) + ((uint)s[1] << 16);
}
return result;
}
private static string ByteArrayToHexViaLookup32(byte[] bytes)
{
char[] result = new char[bytes.Length * 3];
for (int i = 0; i < bytes.Length; i++)
{
uint val = _lookup32[bytes[i]];
result[3 * i] = (char)val;
result[3 * i + 1] = (char)(val >> 16);
result[3 * i + 2] = (" ".ToCharArray())[0];
}
return new string(result);
}

или на:

Неизменяемая часть
txtBoxRespons.Text = ByteToHexBitFiddle(bytes1);
[...]
static string ByteToHexBitFiddle(byte[] bytes)
{
char[] c = new char[bytes.Length * 3];
int b;
for (int i = 0; i < bytes.Length; i++)
{
b = bytes[i] >> 4;
c[i * 3] = (char)(55 + b + (((b - 10) >> 31) & -7));
b = bytes[i] & 0xF;
c[i * 3 + 1] = (char)(55 + b + (((b - 10) >> 31) & -7));
c[i * 3 + 2] = (" ".ToCharArray())[0];
}
return new string(c);
}

результат будет тот же. Возможно, и скорость будет выше. Но, стоит ли так делать?
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Каждый сам для себя решает - хорошие он пишет программы или посредственные, заботится он о пользователях с ограниченными ресурсами, или "у меня на 8-ми ядерном проце с 64Гб оперативы и 3-мя наисвежайшими видюхами за полштуки каждая всё летает" и на офисных нищебродов можно забить
Опять же - одно дело задача исполняющаяся раз в год, и объём обрабатываемых данных "пять строк" - где разница будет между 100 микросекунд и 1 микросекунда, и реально массивная задача и оптимизация позволит обойтись минутами вместо десятков часов.
Это всё касается совершенно любой среды и языка, конечно же.


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Igor Korolyov
Каждый сам для себя решает...

Однозначно!

Спасибо за помощь.
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Главное что - главное ЗНАТЬ
В этом конкретном случае - про наличие альтернативных вариантов существенно ускоряющих работу. Если потребуется - сможешь хорошо всё ускорить. Даже если изначально выбрал просто "самый читаемый" вариант


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Глядя на:

StreamReader txtFile1 = new StreamReader(@"c:\temp\ttt.txt");
BinaryReader binFile1 = new BinaryReader(txtFile1.BaseStream);
byte[] bytes1 = new byte[txtFile1.BaseStream.Length];
int count = binFile1.Read(bytes1, 0, (int)txtFile1.BaseStream.Length);
txtFile1.Close();

Такая вот мысль посетила - можно немного сократить код:

StreamReader txtFile1 = new StreamReader(@"c:\temp\ttt.txt");
BinaryReader binFile1 = new BinaryReader(txtFile1.BaseStream);
byte[] bytes = binFile1.ReadBytes((int)txtFile1.BaseStream.Length);
txtFile1.Close();
Ratings: 0 negative/0 positive
Re: Переввести в 16-ричный вид
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Можно - но за счёт этого он станет в 1.5-2 раза медленнее работать на больших файлах

А вообще для произвольных файлов гораздо лучше заниматься их трансформацией по частям, а не гнать целиком в память... Т.е. считал, к примеру, 1Мб данных, "перекодировал", записал в выходной файл и читай следующую порцию.
Или же вообще поставить в промежуток цепочки потоков BufferedStream и читать/писать по одному символу за раз Но это я не проверял - может оказаться и весьма неэффективным вариантом.


------------------
WBR, Igor
Ratings: 0 negative/0 positive


Извините, только зарегистрированные пользователи могут оставлять сообщения в этом форуме.

On-line: 5 (Гостей: 5)

© 2000-2024 Fox Club 
Яндекс.Метрика