Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: C#, структура и буфер с данными  (Прочитано 8206 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Daniloff
Помогающий

ru
Offline Offline

« : 14-09-2010 12:26 » 

Имеется файл заранее известного формата.

В С++ для его загрузки в память я описываю структуру, выделяю память, подгружаю данные из файла в выделенную область и обращаюсь к ней через указатель структуры. Элементарно.

А вот как быть с C#?..  Здесь была моя ладья...
Записан
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 14-09-2010 12:38 » 

Можно воспользоваться классом BitConverter, он имеет методы для преобразования последовательности байтов в основные скалярные типы-значения. Сами байты получать из потока, связанного с файлом.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 14-09-2010 15:54 » 

Я сам такой задачи не решал, но, по-моему, стоит смотреть в пространство имён System.Runtime.Serialization.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
KoctyaGold
Новенький

ru
Offline Offline

« Ответ #3 : 15-09-2010 11:45 » 

Если у вас предопределена структура файла, тогда можно использовать селиализацию.
Но это медленный способ, чтобы заставить вашу программу быстрее работать, нужно применить маршалинг.
Что я имею ввиду:
Для того, чтобы прочитать какой-то файл, вы сначала предопределяете его структуру:
пример:
Код:
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public struct MyStruct
{
public int field1;
public uint field1;
public float field1;
public long field1;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public int[] array;// в єтом случае будет считываться массив из 2 элементов
};
Только это должна быть структура, а не класс, или все что угодно, что не возвращает по умолчанию null
далее, чтобы прочитать файл, используйте такой код:

Код:

MyStruct entry = reader.ReadStruct<MyStruct>();


Код:
public static unsafe T ReadStruct<T>(this BinaryReader reader) where T : struct
{
byte[] rawData = reader.ReadBytes(Marshal.SizeOf(typeof(T)));

GCHandle handle = GCHandle.Alloc(rawData, GCHandleType.Pinned);
T returnObject = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));

handle.Free();

return returnObject;
}

Этот код работает раз в 10 быстрее чем сериализация, но минус в том, что это небезопасный контекст, и чтоб скомпилировать его, нужно применить флаг компилятора /unsafe

ЗЫ. Как читать сам файл или какими методами решать вам, я вам привел всего лишь пример, и но довольно таки ужатый.
Проблема в том, что обычно файлы бывают сложных структур, и для каждого нужна своя логика, если вам не понятно или будут вопросы - спрашивайте.

Пример функции чтения подобного файла табличной структуры с заголовочными параметрами.
http://paste2.org/p/988835
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 15-09-2010 14:24 » 

Если данные записаны в специфическом формате, когда обычная сериализация не работает, можно написать собственную - через Reflections находить поля структуры, определять их типы и согласно ним вызывать либо методы чтения простых типов у BinaryReader с нужными преобразованиями, либо рекурсивно вызывать эту же функцию для вложенных структур.

Но Reflections работает небыстро.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
KoctyaGold
Новенький

ru
Offline Offline

« Ответ #5 : 15-09-2010 19:42 » 

Цитата
Если данные записаны в специфическом формате, когда обычная сериализация не работает, можно написать собственную
В данном случае, надо описание структуры файла, чтоб знать что посоветовать автору. Ибо все зависит от структуры файла, и вариант его чтения могут быть разными.
Записан
Daniloff
Помогающий

ru
Offline Offline

« Ответ #6 : 16-09-2010 05:08 » 

файл состоит из байтовых полей фиксированной длины.
byte[100], byte[8],byte[8],byte[8],byte[12]...
Записан
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 16-09-2010 05:38 » 

Ну это простой случай. Интереснее когда структура содержит указатели, например
Код:
struct Data
{
  struct Data *Next;
  struct Data *Prev;

// something else
}

Unsafe код - это некрасиво. Какие тогда есть варианты, кроме прослойки на "плюсах"?
Записан
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 16-09-2010 05:53 » 

А в чем заключается смысл хранения указателей в файле?
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #9 : 16-09-2010 05:57 » 

файл состоит из байтовых полей фиксированной длины.

Массивы байтов просто считываются из потока методом Read.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #10 : 16-09-2010 06:06 » 

Dale, забыл дописать. Естесственно не в файле. В памяти. Когда получаешь данные извне. Причем бывает еще и так, что эти поля содержат на самом деле не указатель (хотя объявлены именно так), а смещение относительно начала буфера.
Записан
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #11 : 16-09-2010 06:13 » 

Unsafe код - это некрасиво. Какие тогда есть варианты, кроме прослойки на "плюсах"?

Я в таких случаях добавляю фабричный метод, который умеет считывать экземпляр из двоичного потока (и метод для записи в поток, если требуется).
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #12 : 16-09-2010 06:19 » 

Причем бывает еще и так, что эти поля содержат на самом деле не указатель (хотя объявлены именно так), а смещение относительно начала буфера.

Мое IMHO: если поле объявлено как указатель и при этом хранит совершенно другие данные, таким объявлением лучше не пользоваться. Поскольку никто не мешает описать смещение именно как смещение. К тому же размер указателя зависит от разрядности платформы.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #13 : 16-09-2010 21:43 » 

К тому же размер указателя зависит от разрядности платформы.

Ну и что?

если поле объявлено как указатель и при этом хранит совершенно другие данные, таким объявлением лучше не пользоваться. Поскольку никто не мешает описать смещение именно как смещение

Ну это ты просто не сталкивался с такими ситуациями, когда так приходится делать. Иногда требуется скопировать буфер из одного адресного пространства в другое. Допустим, ты объявишь структуру, в которой будут и поля-указатели и поля-смещения. Когда ты скопируешь буфер, указатели сразу станут невалидными. И для того, чтобы данные в этом новом буфере можно было прочитать, тебе надо будет перед копирование высчитать смещения, и занести их в соответствующие поля. Код который потом обрабатывает новый буфер естесствено не будет каждый раз, при доступе к данным, гемороиться со смещениями. Он пересчитает смещения в указатели (уже валидные). Таким образом, получается, что у тебя в структуре будут поля которые будут использованы один раз в жизни, и при этом (именно в это время) у тебя будут другие неиспользуемые поля (такое же их количество). Короче говнокод получится.

По поводу считывания экземпляров из двоичного потока. Есть одно простое правило в C#: если используются указатели (даже внутри каких-то объектов), то это unsafe код. Пусть даже это будут какие-то дотнетовские объекты, а не твой код - все равно некрасиво. Само по себе, даже думать об указателях в C# это уже выходит за рамки его гармоничного мира. Для этого и делается плюсовая прослойка. Это что касается философии шарпа. Но если говорить о технической стороне, то выходит примерно тоже самое. Нельзя никак полагать что, то что в плюсах было указателем сойдет за ссылку на объект или что-то в этом духе.
Записан
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #14 : 17-09-2010 05:25 » 

К тому же размер указателя зависит от разрядности платформы.

Ну и что?

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

Ну это ты просто не сталкивался с такими ситуациями, когда так приходится делать. Иногда требуется скопировать буфер из одного адресного пространства в другое. Допустим, ты объявишь структуру, в которой будут и поля-указатели и поля-смещения. ... Короче говнокод получится.

Для подобных говнокодов специально заточен С, на котором всякие хаки делаются легко и непринужденно. C# несколько на другие задачи ориентирован, выбор его для кульбитов с адресными пространствами выглядит странновато.

И вообще неплохо бы ответить на вопрос, который задал автор темы. А спросил он вполне конкретную вещь: как считать двоичные данные из файла в структуру. Когда спросит о копировании буфера из одного адресного пространства в другое, это будет уже другая тема.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #15 : 20-09-2010 20:47 » 

Да то что указатель хранится в структуре, это не означает, что его надо хранить в файле. Какие вообще в файле могут храниться указатели. Для этого и придумали смещения.

Цитата: Dale
Для подобных говнокодов специально заточен С, на котором всякие хаки делаются легко и непринужденно. C# несколько на другие задачи ориентирован, выбор его для кульбитов с адресными пространствами выглядит странновато

Я, собственно, изначально сказал, что в таких ситуациях обычно делают "прослойку" на плюсах (если по-хорошему).

Цитата: Dale
И вообще неплохо бы ответить на вопрос, который задал автор темы

А что, еще не ответили?

Цитата: Dale
Когда спросит о копировании буфера из одного адресного пространства в другое, это будет уже другая тема.

Извините пожалуйста. Больше не буду.
Записан
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #16 : 20-09-2010 21:44 » 

А что, еще не ответили?.

Судить автору. Если сможет в этом разнообразии отыскать практически применимый ответ на первоначально заданный вопрос, то можно считать, что ответили.

Извините пожалуйста. Больше не буду.

Ну что вы, оставьте... Было чрезвычайно познавательно.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines