считать из файла в структуру

Язык Visual Basic на платформе .NET.

Модераторы: Ramzes, Sebas

salvequick
Новичок
Новичок
 
Сообщения: 25
Зарегистрирован: 27.09.2007 (Чт) 10:24

считать из файла в структуру

Сообщение salvequick » 27.09.2007 (Чт) 10:51

проблема не могу считать из файла сразу в структуру как в С.

читал статьи на сайте Vbstreets
Гайдар Магдануров Переход на VB.NET, статья №5 Работа с файлами
Работа с памятью и указателями в VB.NET

понял что это возможно но не пойму как.
в файлы пишет программа написанная в VB6
у меня есть только опыт разработки на С и С++
basic мне знаком только по MS Basic PDS 7.1 еще под DOS

вопросы:

вот такая струкрура не объявляется у меня
ругается на StructLayout и на MarshalAs

Код: Выделить всё
<StructLayout(LayoutKind.Sequential, Pack:=1, CharSet:=CharSet.Unicode)> Structure UserType
      <MarshalAs(UnmanagedType.ByValArray, SizeConst:=4)> Public b() As byte
      <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=16)> Public c As String
      <MarshalAs(UnmanagedType.LPWStr)> Public s As String
End Structure


я так понимаю что она будет аналогична

Код: Выделить всё
typedef struct _usertype {
      BYTE b[4];
      wchar_t c[16];
      LPWSTR s;
} usertype;



а если оперировать простыми типами
а вот какой аналог будет у такой структуры??? как ее считать с диска?

Код: Выделить всё
struct A
{
int i;
float f;
double d;
char t[12];
unsigned int ui;
unsigned char uch;
unsigned double ud[20];
};



заранее спасибо за советы!!!

salvequick
Новичок
Новичок
 
Сообщения: 25
Зарегистрирован: 27.09.2007 (Чт) 10:24

часть проблемы решил ...

Сообщение salvequick » 27.09.2007 (Чт) 11:29

Imports System.Runtime.InteropServices

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Re: считать из файла в структуру

Сообщение Viper » 27.09.2007 (Чт) 13:37

salvequick писал(а):
Код: Выделить всё
struct A
{
int i;
float f;
double d;
char t[12];
unsigned int ui;
unsigned char uch;
unsigned double ud[20];
};

Аналог будет вида:
Код: Выделить всё
<StructLayout(LayoutKind.Sequential)> Structure A
Public i As Integer
Public f As Single
Public d As Double
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=12)> Public  t() As Char
Public ui As UInt32
Public uch As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=20)> ud() As Double
End Structure


З.Ы. unsigned double не бывает!
З.З.Ы. Еще раз читать упомянутые статьи на основном сайте. До просветления.
Весь мир матрица, а мы в нем потоки байтов!

salvequick
Новичок
Новичок
 
Сообщения: 25
Зарегистрирован: 27.09.2007 (Чт) 10:24

Сообщение salvequick » 27.09.2007 (Чт) 14:28

вообщем на диске лежит такая вот С структура

Код: Выделить всё
struct str
{
int i;
char t[12];
float floati;
double doublei;
};


вот как я пытаюсь ее считывать... не получается пока....
не понятно как то что я считаю используя BinaryReader допустим
массив i() as byte преобразовать к структуре ComStr в конечном счете

char тут имеется ввиду однобайтный символы
поэтому я написал так
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=12)> Dim t() As Byte '12

Код: Выделить всё
Public Class Form1

    <StructLayout(LayoutKind.Sequential, Pack:=1, CharSet:=CharSet.Ansi)> Private Structure ComStr
        <MarshalAs(UnmanagedType.I4)> Dim i As Integer  '4
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=12)> Dim t() As Byte  '12
        <MarshalAs(UnmanagedType.R4)> Dim floati As Single '4
        <MarshalAs(UnmanagedType.R8)> Dim doublei As Double '8
    End Structure

    <StructLayout(LayoutKind.Sequential, Pack:=1, CharSet:=CharSet.Ansi)> Private Structure ByteArr
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=28)> Dim t() As Byte  '28
    End Structure


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

   Dim f As ComStr
   Dim binReader As New BinaryReader(File.Open("/testfile_c", FileMode.Open, FileAccess.Read))

   Dim p As IntPtr = Marshal.AllocHGlobal(28)     ' получаем указатель на блок памяти

  Dim bit As ByteArr

        'считать в блок неуправляемой памяти
        bit.t = binReader.ReadBytes(28)

        'скопировать сырые данные в выделенную память
        Marshal.StructureToPtr(bit.t, p, True)

        'скопировать из выделенной памяти в структуру ComStr
        Dim f2 As ComStr = CType(Marshal.PtrToStructure(p, GetType(ComStr)), ComStr)          ' создаем копию исходного объекта

        binReader.Close()

end sub

end class


на этой строчке ошибка
Marshal.StructureToPtr(bit.t, p, True)

вот текст доп информации:
Additional information: The specified structure must be blittable or have layout information.

хотя вроде бы структура эта объявлена со всеми атрибутами

Статьи естественно читаю :))) ну пока вот что то никак....
непонятно

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Сообщение Viper » 27.09.2007 (Чт) 15:40

salvequick писал(а):на этой строчке ошибка
Marshal.StructureToPtr(bit.t, p, True)

вот текст доп информации:
Additional information: The specified structure must be blittable or have layout information.


еще бы! Ты передаешь в функцию не структуру, а член структуры, в данном случае массив, оставь просто bit.

Читать статью дальше. Жди просветления.

З.Ы. Код чтения через пятую точку, да еще и не одну. Все делается гораздо проще.
Весь мир матрица, а мы в нем потоки байтов!

salvequick
Новичок
Новичок
 
Сообщения: 25
Зарегистрирован: 27.09.2007 (Чт) 10:24

Сообщение salvequick » 28.09.2007 (Пт) 8:39

Viper писал(а):З.Ы. Код чтения через пятую точку, да еще и не одну. Все делается гораздо проще.


хоть какую функцию то проще использовать?
с какой проще всего работать?
т..е какая максимально ближе к
Код: Выделить всё
open()
read()  write()
close()


вот такой вариант еще имеется вроде бы
Код: Выделить всё
        Dim fFile As Short
        fFile = FreeFile()
        FileOpen(fFile, "/testfile_c", OpenMode.Random, FileAccess.Read)
        FileGet(fFile, f)
        FileClose(fFile)


а еще и такой метод

Код: Выделить всё
       
        Dim fstream As New FileStream("/testfile_c", FileMode.Open)
        Dim sr As New StreamReader(fstream, System.Text.Encoding.ASCII)
        sr.Read()
        sr.Close()


чорт ногу сломит

:(( куча каких то функци ....что то средства языка я так понял ...какие то .NET классы для файлов...что то из функций в Win 32 API есть....

salvequick
Новичок
Новичок
 
Сообщения: 25
Зарегистрирован: 27.09.2007 (Чт) 10:24

Сообщение salvequick » 28.09.2007 (Пт) 9:14

Viper писал(а):
salvequick писал(а):на этой строчке ошибка
Marshal.StructureToPtr(bit.t, p, True)

вот текст доп информации:
Additional information: The specified structure must be blittable or have layout information.


еще бы! Ты передаешь в функцию не структуру, а член структуры, в данном случае массив, оставь просто bit.



если тут оставить просто bit то получается другая ситуация

Additional information: Cannot marshal field 't' of type 'ByteArr': Invalid managed/unmanaged type combination (Arrays fields must be paired with ByValArray or SafeArray).

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Сообщение Viper » 28.09.2007 (Пт) 10:29

Ну так тебе правильно пишется насчет ByValArray, его и надо указывать.

По поводу реализации желаемого:
1. Можно последовательно прочитать поля структуры соответствующими методами класса BinaryReader (Read...). Сей метод логичнее и проще.
2. Можно прочитать данные в массив соответствующего размера (запихивать его в структуру, как у тебя сделано, совершенно не нужно), скопировать массив в блок памяти, далее сотворить структуру из этого блока памяти. Метода конечно кривенькая, но работает. Чтение в массив делаем через ReadBytes, далее соответствующие методы класса Marshal.
3. Лезть в API... и читать данные непосредственно в структуру путем использования нужным образом объявленной функции ReadFile. При работе в NET это некошерный способ конечно, но вполне законный.

З.Ы. Еще раз читать мою статью, там про все методы возни с памятью очень хорошо писано. Просветление таки наступит.
Весь мир матрица, а мы в нем потоки байтов!

salvequick
Новичок
Новичок
 
Сообщения: 25
Зарегистрирован: 27.09.2007 (Чт) 10:24

Сообщение salvequick » 28.09.2007 (Пт) 10:47

мне бы наверное второй способ подошел ну или третий.. ...

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

salvequick
Новичок
Новичок
 
Сообщения: 25
Зарегистрирован: 27.09.2007 (Чт) 10:24

Сообщение salvequick » 28.09.2007 (Пт) 11:39

вот тогда пролучается ....
Код: Выделить всё
 
    <StructLayout(LayoutKind.Sequential, Pack:=1, CharSet:=CharSet.Ansi)> Private Structure ComStr
        <MarshalAs(UnmanagedType.I4)> Dim i As Integer  '4
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=12)> Dim t() As Byte  '12
        <MarshalAs(UnmanagedType.R4)> Dim floati As Single '4
        <MarshalAs(UnmanagedType.R8)> Dim doublei As Double '8
    End Structure

    <StructLayout(LayoutKind.Sequential, Pack:=1, CharSet:=CharSet.Ansi)> Private Structure ByteArr
        <MarshalAs(UnmanagedType.ByValArray, SizeConst:=28)> Dim t() As Byte  '28
    End Structure


        Dim p As IntPtr = Marshal.AllocHGlobal(28)     ' получаем указатель на блок памяти
        Dim m(28) As Byte ' из него не получается скопировать данные нет StructLayot
        Dim bit As ByteArr
        Dim fFile As Short

        fFile = FreeFile()

        FileOpen(fFile, "/testfile_c", OpenMode.Binary, FileAccess.Read)
        FileGet(fFile, bit,28)  'читаем в массив данных
        FileClose(fFile)
   
        'скопировать сырые данные в выделенную память
        Marshal.StructureToPtr(bit, p, True)

        'скопировать из выделенной памяти в структуру ComStr
        Dim f2 As ComStr = CType(Marshal.PtrToStructure(p, GetType(ComStr)), ComStr)          ' создаем копию исходного объекта


читать в массив байт m получается .... но тогда
Код: Выделить всё
Marshal.StructureToPtr(m, p, True)
ругается на то что нету StructLayot и не может скопировать ничего

если читать в структуру bit as ByteArr то здесь получается ошибка на
Код: Выделить всё
FileGet(fFile, bit,28)  'читаем в массив данных


пробовал так даже
Код: Выделить всё
FileGet(fFile, bit,1)  'читаем в массив данных


но вообщето третий параметр это bytenumber для Binarymodes файлов

Additional information: Unable to read beyond the end of the stream.

всеж правильно вроде.... куда уж правильнее то ....

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Сообщение Viper » 28.09.2007 (Пт) 11:56

Что ж все в кучу то свалено? Ужасть! Таки придется примером показать...
Весь мир матрица, а мы в нем потоки байтов!

salvequick
Новичок
Новичок
 
Сообщения: 25
Зарегистрирован: 27.09.2007 (Чт) 10:24

Сообщение salvequick » 28.09.2007 (Пт) 13:02

ну пока вот в голове именно так все выглядит :)))
совершенно не устаканивается

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Пример

Сообщение Viper » 28.09.2007 (Пт) 13:06

Держи пример.

Реализованы вариант 1 и 2. Над третьим, уж будь добр, потрудись сам. Если есть вопросы, то всегда пожалуйста.
Вложения
Main.rar
(1.15 Кб) Скачиваний: 102
Весь мир матрица, а мы в нем потоки байтов!

salvequick
Новичок
Новичок
 
Сообщения: 25
Зарегистрирован: 27.09.2007 (Чт) 10:24

Сообщение salvequick » 28.09.2007 (Пт) 13:29

ну я даже не знаю ... спасибо!!! :oops:
:)))))

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Сообщение Viper » 28.09.2007 (Пт) 13:39

Да пожалуйста. :)
З.Ы. Для третьего варианта ключевые слова для поиска в MSDN: CreateFile, ReadFile, CloseHandle (это необходимые для чтения функции) и Declare и DLLImport для их объявления в VB.NET.
Весь мир матрица, а мы в нем потоки байтов!

salvequick
Новичок
Новичок
 
Сообщения: 25
Зарегистрирован: 27.09.2007 (Чт) 10:24

Сообщение salvequick » 28.09.2007 (Пт) 13:48

с API функциями я этими знаком...
я писал на Win32 API на MSVS6 еще ...

Declare и DLLImport для их объявления в VB.NET

у меня проблема с Basic будет и .NET


спасибо еще раз :)


Вернуться в Visual Basic .NET

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 70

    TopList