#c_sharp #инспекция_кода #byte
Программа читает бинарные данные из файла. У меня был пример чтения, на основе которого, я реализовал данный пример записи.Общий смысл: есть заголовок файла (это код до слов "пишем данные"). С заголовком все просто. Пишется без всяких преобразований. Далее пишется маска и после маски пишутся 3 значения переменных. В маску пишется сколько байт каждое из чисел занимает. Код: public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void ConnectButton_Click(object sender, RoutedEventArgs e) { // Переменная хранит путь к файлу string file_path = "ResultFile.rls"; // Удаляем файл, если он есть if (File.Exists(file_path)) { File.Delete(file_path); } // Создаем файл FileStream fs = File.Open(file_path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write); // Поток для записи в файл BinaryWriter bw = new BinaryWriter(fs); // Пишем размерность. Double bw.Write(-1.0); // Пишем какую то хрень. int32. bw.Write(2); // Количество записей. int32. bw.Write(5); // Val1. Double bw.Write(6800.0); // Val2. Double bw.Write(6800.0); // Val3. Double bw.Write(6800.0); // Val4 Double bw.Write(6800.0); // DateTime. Int64 bw.Write(new DateTime(2015, 03, 12, 23, 0, 0).Ticks); // Val5. Int64 bw.Write((Int64)2); // пишем данные AddItem(bw, 5, 10, 0); AddItem(bw, 1, 0, 1); AddItem(bw, 3, 20, 3); AddItem(bw, 5, 60, 1); AddItem(bw, 4, 80, 2); bw.Close(); fs.Close(); } // Функция отрезает не значимые значения массива byte[] CutZero(byte[] in_array) { // Список байт Listresult; // Инициализируем список result = new List (); // Переменная определяет, что пора начинать копирование bool ready_to_copy = false; // В цикле перебираем каждый байт переданного массива с конца for (int i = in_array.Length - 1; i >= 0; i--) { // Если это не нулевой байт, то начинаем копирование if (in_array[i] != 0x00) { ready_to_copy = true; } // Если копирование началось if(ready_to_copy) { result.Add(in_array[i]); } } // Возвращаем полученный массив return result.ToArray(); } // Добавить данные в файл private void AddItem(BinaryWriter _bw, int _vol, int _dp, int _dt) { // 1.Считаем переменные // 1.1. Val1 byte[] vol = CutZero(BitConverter.GetBytes(_vol)); // 1.2. Val2 byte[] dp = CutZero(BitConverter.GetBytes(ConvertVal2Bytes(_dp))); // 1.3. Val3 byte[] dt = CutZero(BitConverter.GetBytes(_dt)); // 1. Количество байт. Сразу пишем в двоичном виде string str_length = "0"; // 1.1. Для Val1 str_length += ConvertFromVal1(vol.Length); // 1.2. Для Val2 str_length += ConvertFromVal2(dp.Length); // 1.3. Для Val3 str_length += ConvertFromVal3(dt.Length); // Пишем маску _bw.Write(Convert.ToByte(str_length, 2)); // Val3 _bw.Write(dt); // Val2 _bw.Write(dp); // Val1 _bw.Write(vol); } // Конвертируем байты private byte ConvertVal2Bytes(int _dp) { byte result; // Получим массив байт, для определения длины byte[] dp = CutZero(BitConverter.GetBytes(_dp)); // В зависимости от количества байт добавляем дельты switch (dp.Length) { case 0: { // Ничего не добавляем result = (byte)_dp; break; } case 1: { result = (byte)((byte)_dp + 0x80); break; } case 2: { result = (byte)((byte)_dp + 0x400); break; } case 4: { result = (byte)((byte)_dp + 0x4000000); break; } default: { result = (byte)_dp; break; } } // Возвращаем результат return result; } // Конвертируем длину в двоичное представление private string ConvertFromVal3(int length) { string result = ""; switch (length) { case 0: result = "00"; break; case 1: result = "01"; break; case 2: result = "10"; break; case 3: result = "11"; break; default: break; } return result; } // Конвертируем длину в двоичное представление private string ConvertFromVal2(int length) { string result = ""; switch (length) { case 0: result = "00"; break; case 1: result = "01"; break; case 2: result = "10"; break; case 4: result = "11"; break; default: break; } return result; } // Конвертируем длину в двоичное представление private string ConvertFromVal1(int length) { string result = ""; switch (length) { case 1: result = "001"; break; case 2: result = "110"; break; case 4: result = "111"; break; case 8: result = "010"; break; default: break; } return result; } } Все работает. Но у меня есть такое ощущение, что можно как то это упростить. Я не работал ни разу с байтами / битами. Возможно часть кода можно заменить какими то стандартными функциями. Очень было бы поучительно.
Ответы
Ответ 1
Например, функцию CutZero можно представить на LINQ так: IEnumerableCutZero(IEnumerable in_array) { return in_array.Reverse().SkipWhile(b => b == 0x00); } Затем, код (byte)((byte)_dp + 0x400) выглядит странно: прибавление 0x400 не затрагивает младший байт, так что после преобразования к (byte) он всё равно отбросится. Затем, ConvertFromVal3 — это перевод в двоичное представление? Его можно легко заменить на встроенную функцию: Convert.ToString(length, 2).PadLeft(2, '0') Затем, совершенно неясно, что делают функции ConvertFromVal2 и ConvertFromVal1. Они не конвертируют в двоичное представление (т. к., например, двоичное представление для 4 будет никак не "111"), но возвращают явно двоичные строки. Затем, конвертация чисел в строку лишь для того, чтобы потом склеить и сконвертировать назад, выглядит как-то совсем странно. Если вы хотите склеить биты, применяйте битовые операции: private byte ConvertFromVal3(int length) { if (length < 0 || length > 3) throw new ArgumentException(...); return (byte)length; } private byte ConvertFromVal2(int length) { switch (length) { case 0: return (byte)0; case 1: return (byte)1; case 2: return (byte)2; case 4: return (byte)3; default: throw new ArgumentException(...); } } private byte ConvertFromVal1(int length) { switch (length) { case 1: return (byte)1; case 2: return (byte)6; case 4: return (byte)7; case 8: return (byte)2; default: throw new ArgumentException(...); } } // ... // 1. Количество байт. Сразу пишем в двоичном виде byte lengths = 0; // 1.1. Для Val1 lengths |= (ConvertFromVal1(vol.Length) << 4); // 1.2. Для Val2 lengths |= (ConvertFromVal2(dp.Length) << 2); // 1.3. Для Val3 lengths |= ConvertFromVal3(dt.Length); // Пишем маску _bw.Write(lengths); Ответ 2
Если под упростить подразумевается уменьшение количества строк кода, то можно в ConnectButton_Click вместо многократных bw.Write(...) значения поместить в массив и вывести их в цикле. А ConvertFromVal3, например, определить так: private string ConvertFromVal3(int length) { var arr = new[] { "00", "01", "10", "11" }; return length < arr.Length ? arr[length] : ""; }
Комментариев нет:
Отправить комментарий