
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.97.9.175] |
![]() |
|
Сообщ.
#1
,
|
|||||||||||||||||||
|
Здравствуйте Уважаемые!
Очень много вопросов, по стандарным методам и свойствам VB, таким, как файловый ввод и вывод. Надоело ![]() Файлы Итак, вы познакомились с некоторыми средствами ввода информации. Однако эту информацию зачастую требуется не только анализировать, но и сохранять. Для сохранения информации предназначены операторы обработки файлов, позволяющие считывать и сохранять данные на различных носителях (гибкий либо жесткий диск и т.п.). Процесс открытия и сохранения файлов состоит из нескольких этапов: * получение дескриптора файла (Handle); * открытие файла; * чтение или запись данных; * закрытие файла. Дескриптор файла Чтобы работать с файлами, нужно понимать, как связывается система или приложение с файлом. Для этого имеется канал ввода/вывода. При открытии файлу ставится в соответствие канал с определенным номером. Таким образом, каждый открытый файл имеет собственный канал, с помощью которого записываются или считываются данные. Следовательно, для ввода и вывода данных в файл имеет значение не имя файла, а номер канала. Кроме того, операционная система должна иметь сведения о наличии свободных каналов, которые можно использовать для открытия файла. FreeFile Функция Visual Basic FreeFile возвращает номер свободного канала, который можно использовать для работы с файлом. ![]() ![]() FreeFile[(RangeNumber)] Если свободных каналов нет (открыто максимально допустимое количество файлов), возникает ошибка выполнения. ![]() ![]() intFH=FreeFile В этом примере переменной intFH присваивается целое значение, которое можно использовать для открытия файла. Необязательный параметр RangeNumber позволяет определить диапазон значений, из которого выбирается очередной свободный номер канала. Если его значение равно 0 (по умолчанию), то возвращается номер канала из диапазона 1 – 255, если 1, то из диапазона 256 – 511. Типы доступа В Visual Basic реализованы три типа доступа к файлам: * последовательный (Sequential) – для чтения и записи текстовых файлов; * произвольный (Random) – для чтения и записи текста или структурированных двоичных файлов с записями фиксированной длины; * двоичный (Binary) – для чтения и записи произвольно структурированных файлов. При создании коммуникационных каналов система должна знать, какой тип доступа к каждому конкретному файлу нужно использовать и какова структура данных этого файла. Последовательный доступ Последовательный доступ используется главным образом при работе с текстовыми файлами. Любая информация считывается или сохраняется в текстовом виде построчно. В тексте могут находиться символ перевода строки (vbCrLf или Chr (13) & Chr (10)) или табулятор (Tab или Chr (9)). Эти символы используются для форматирования текста. Способ открытия файла с последовательным доступом (для чтения, записи или добавления) задается при вызове оператора Open: ![]() ![]() Open FileName For [Input | Output | Append] As FileHandle Таблица 1. Различные операционные возможности для последовательного доступа.
Если файл не существует и открывается для чтения (For input), то Visual Basic выдает сообщение об ошибке, а если для записи или добавления (Output или Append), то создается новый файл. Если файл с указанным именем существует, то в режиме Output его содержимое удаляется, а в режиме Append файл открывается для добавления: ![]() ![]() Open "C:\README.TXT" For Input As intFH1 Open "C:\DATA\TEXT.TXT" For Output As intFH2 Open "C:\USERS.TXT" For Append As intFH3 В конце строки указывается номер канала, возвращаемый функцией FreeFile. В некоторых операционных системах, например в Windows 95/98, можно использовать длинные имена файлов. Чтение из файла Для считывания данных из файла, открытого для последовательного доступа, существует несколько возможностей. В общем случае это осуществляется с помощью оператора Input, имеющего несколько разновидностей: * Line lnput# считывает одну строку; * Input# считывает последовательность символов, обычно записанных с помощью оператора Write#; * Input$ считывает определенное количество символов. Существует несколько вариантов чтения всей информации из файла. Перед чтением нужно открыть файл с помощью оператора Open… For: ![]() ![]() intFH = FreeFile Open "С:\Text.Txt" For Input As #intFH 'Первый вариант Do Until EOF(intFH) Line Input #intFH, strString strText = strText & strString & vbLf Loop 'Второй вариант StrText = Input$(LOF(intFH), intFH) Close #intFH Оба варианта приводят к одинаковому результату. В первом варианте оператор Input выполняется в цикле, пока не будет, достигнут конец файла. Функция EOF (End Of File) возвращает значение True при достижении конца файла. При этом на каждом шаге цикла считывается отдельная строка и к ней добавляется символ конца строки, который отбрасывается оператором Line Input. Во втором варианте весь файл считывается функцией Input$. Функция LOF (Length Of File) позволяет определить длину файла в байтах. Заметим также, что независимо от вида оператора Input указывается не FileName (имя файла), а только номер канала, т.е. дескриптор файла (intFH). Close Оператор Close предназначен для закрытия открытого файла или канала. Запись в файл В Visual Basic для записи информации в файл используются операторы Print# и Write#. Print# Оператор Print# функционирует почти так же, как его коллега для экрана, с той лишь разницей, что данные не выводятся на экран, а сохраняются в файле, открытом для записи или добавления (Open… For Output или Open… For Append). ![]() ![]() Print #FileHandle, [(Spase(n)| Tab[(n)]] [Expression] [Charpos] Синтаксис оператора на первый взгляд выглядит сложно: ![]() ![]() Print #intFH, Text1.Text Print #intFH, "Фрагмент 1", "Фрагмент 2" Print #intFH, "Это составляет "; "единое целое" Для форматирования записываемой в файл информации следует по-разному разделять данные в операторе Print. Если в операторе данные разделять запятыми [,], то в файле они будут разделены символами табуляции: ![]() ![]() Print #intFH, "Фрагмент 1", "Фрагмент 2" 'соответствует Print #intFH, "Фрагмент 1"; Tab; "Фрагмент 2" Если же в операторе для разделения данных использовать точку с запятой [;], то данные в файл записываются без разделителей: ![]() ![]() Print #intFH, "Это составляет "; "единое целое" 'соответствует Print #intFH, "Это составляет единое целое" Write# Оператор Write# имеет такой же синтаксис, что и Print#. Отличие состоит только в форматировании вывода. Если Print# сохраняет данные в виде обычного текста, то Write# заключает текстовые строки в кавычки, а цифры выводятся без кавычек: ![]() ![]() Print #intFH, "Анна", "Киев", 17 'В файле будет: Анна Киев 17 Write #intFH, "Анна", "Киев", 17 'В файле будет: "Анна","Киев",17 Данные, сохраненные с помощью оператора Write#, можно считать оператором Input#. Произвольный доступ Доступ типа Random Access несколько утратил свое значение после появления в версии Visual Basic 3.0 средств доступа к базам данным. В отличие от последовательного доступа, при котором данные в файлах хранятся в неструктурированном виде, произвольный доступ предполагает, что файл имеет постоянную структуру. Это позволяет считывать данные в произвольном порядке. Произвольный доступ реализуется посредством оператора Open. ![]() ![]() Open FileName For Random [Access] [Lock] As [#]FileHandle [Len=RecLength] Параметр Len определяет длину записи. Если это значение меньше, чем реальная длина записи, то возникает ошибка, если больше – то при записи файла используется больше дискового пространства, чем необходимо. Параметр Access позволяет задать права доступа к открываемому файлу. Таблица 2. Виды доступа при произвольном доступе.
Если права доступа не указаны, то по умолчанию используется Read Write. Так как этот тип доступа обычно предназначен для работы с файлами, которые могут использоваться многими пользователями или приложениями, то следует обеспечить целостность данных при коллективном использовании. Для этого следует установить параметр Lock, определяющий права доступа к открытому файлу. Этот параметр может принимать следующие значения: * Shared Файл может использоваться всеми процессами для считывания и записи. * Lock Read Никакой другой процесс не может считывать данные из файла. Данный параметр можно установить, если в данный момент никакой другой процесс не выполняет операцию чтения. * Lock Write Никакой другой процесс не может записывать данные в файл. Данный параметр можно установить, если в данный момент никакой другой процесс не выполняет операцию записи. * Lock Read Write Никакой другой процесс не может считывать или записывать. Данный параметр можно установить, если в данный момент не выполняются операции чтения или записи. Параметр Len задает длину одной записи. Для задания длины можно использовать функцию Len: ![]() ![]() Open "ADDRESS.DAT" For Random Access Write As 1 Len = 27 Open "ADDRESS.DAT" For Random Access Write As 1 Len = Len(Varname) При этом важно, чтобы при открытии файла была известна длина набора данных, что может быть проблематичным, если происхождение файла неизвестно. Ввод и вывод Get, Put Для записи и чтения данных используются соответственно операторы Put и Get. ![]() ![]() Put #FileHandle, RecNumber, Variable Get #FileHandle, RecNumber, Variable В примере в файл записываются данные из переменной Address, причем номер записи равен 7, а затем в переменную Address считывается вторая запись файла. ![]() ![]() Put #intFH, 7, Address 'сохраняет 7-ую запись Get #intFH, 2, Address 'считывает 2-ую запись Для того чтобы в одной записи сохранить несколько значений различных типов, следует использовать пользовательские типы данных: ![]() ![]() '(General)(Declaration) Type Person FirstName As String * 20 Name As String * 20 CustomerN As Integer End Type Private Customer As Person 'Процедура Private Sub Command1_Click() intFH = FreeFile Open "C:\LORE.DAT" For Random As intFH Len = Len(Customer) Get #intFH, 2, Customer Close #intFH End Sub Двоичный доступ Двоичный доступ незначительно отличается от произвольного доступа. Разница состоит только в том, что двоичный доступ возможен не к определенному набору данных, а к отдельному байту внутри любого файла. Open Для открытия двоичного файла также используется оператор Open. ![]() ![]() Open FileName For Binary [Access] [Lock] As [#] FileHandle Вот и всё что я хотел сказать! ![]() |
![]() |
Сообщ.
#2
,
|
|
Это, типа, реквест на фак? А почему не уведомил как-то?
Добавлено Участникам, читающим раздел: комментировать можно здесь. Если тема пойдет в ФАК, там будет её дубль |
Сообщ.
#3
,
|
|
|
Есть вопрос, я как раз с этим бьюсь уже 2 дня.
Фнукция Get позволяет сохранить несколько байт бинарного файла только если я напишу переменную с множителем на конце: Dim FirstName As String * 20 А как можно изменить этот множитель? У меня он должен быть равен размеру файла. Вопрос 2. Множитель у меня должен быть равен размеру файла, т.к. я считаю, что бинарный файл представляет собой одну громадную строчку. Я прав? И важно сказать здесь, что если вы будете использовать функцию Line Input для получения строки из бинарного файла - у вас не возникнет явных ошибок, но содержимое будет браться с ошибкой!!! |
Сообщ.
#4
,
|
|
|
1)
Цитата Сергей85 @ Фнукция Get позволяет сохранить несколько байт бинарного файла Не сохранить, а прочесть. Длину файла можно узнать через LOF() если файл открыт, передав ему номер канала или используя функцию FileLen(). Выделить буфер можно через функцию Space(). Параметры функций расписаны в справочниках. 2) Цитата Сергей85 @ бинарный файл представляет собой одну громадную строчку. Я прав? Прав |
![]() |
Сообщ.
#5
,
|
|
Цитата Сергей85 @ как можно изменить этот множитель? В рантайме никак. Цитата Сергей85 @ я считаю, что бинарный файл представляет собой одну громадную строчку. Я прав? Нет. Бинарный файл представляет собой поток байтов. И грузить его нужно в массив байтов, а не в строковую переменную. Открыть файл, получить размер, (пере)определить размер массива, загрузить содержимое файла в массив. Далее, если нужно, копировать нужные блоки в (строковые) переменные или использовать напрямую. И лишь в самом крайнем случае использовать загрузку в строковую переменную, инициализируя её необходимым количеством нулей или пробелов. Цитата Сергей85 @ если вы будете использовать функцию Line Input для получения строки из бинарного файла ... то в подавляющем большинстве случаев Вас назовут... ммм... в лучшем случае назовут не очень грамотным программистом. |
Сообщ.
#6
,
|
|
|
Фрагмент (или весь бинарный файл) нужно читать в массив, а его можно задать и фиксированной длины, и динамический. Также можно считывать поэлементно в переменные или сразу в структуры.
|
Сообщ.
#7
,
|
|
|
А как прочитать только одну динамическую переменную структуры из файла, не открывая весь файл?
Уточню: Получить указатель на массив в структуре и измерить (с измерить проблема) и прочитать из файла имено этот массив , не открывая весь файл? я сохраняю структуру z() в файл: Private Type abcd a As String b() As Byte c As Boolean End Type Dim z() As abcd Мне надо вытащить к примеру только z(3) желательно не открывая весь файл |
![]() |
Сообщ.
#8
,
|
|
Вычисляй смещение в файле по размеру структуры * индекс массива и читай Get-ом размер одного элемента
|
Сообщ.
#9
,
|
|
|
Цитата B.V. @ Вычисляй смещение в файле по размеру структуры Я не использую Доступ типа Random пример ниже вариант с Len(z()) не сработает хотя надо поэксперементировать с Random ![]() ![]() Доступ типа Random Access несколько утратил свое значение после появления в версии Visual Basic 3.0 средств доступа к базам данным а что за средств доступа к базам данным? Цитата B.V. @ Сергей85 вот пример ![]() ![]() Option Explicit Private Type RCol NumbsL As Long NumbsI As Integer End Type Private Type HDATA SubName(12) As String Age As RCol End Type: Dim Data(1 To 6) As HDATA Private Sub Command1_Click() Open App.Path & "\test.dat" For Binary Access Read As #1 Get #1, 1, Data Close #1 Dim i% For i = 1 To 3 Text1(0).Text = Data(i).SubName(1) Text1(3).Text = Data(i).SubName(4) Text1(1).Text = Data(i).SubName(3) Text1(2).Text = Data(i).Age.NumbsI MsgBox i Next i End Sub Private Sub Command2_Click() 'Писать в "test.dat" Data(1).Age.NumbsL = 19 Data(1).SubName(1) = "88888888 o работы с файлами" Data(1).SubName(4) = "Писать 11111111 test.dat" Data(2).SubName(4) = "Пис2222222222.dat" Data(2).Age.NumbsI = 15 Data(2).SubName(1) = "Сначала [[[[[[[[[[[[ некоторую память" Data(2).SubName(3) = "Писать 99999999 test.dat" Data(3).Age.NumbsI = 17 Data(3).SubName(1) = "Этот пример показывает как, чтобы" Data(3).SubName(4) = "Писат33333333t.dat" Open App.Path & "\test.dat" For Binary Access Write As #1 Put #1, 1, Data Close #1 End Sub и мои эксперименты с вставкой изображений в файл ![]() |
Сообщ.
#10
,
|
|
|
Рецепт от http://support.microsoft.com/ ищи Работа с файлами двоичного доступа
Запись файлов, открытых для двоичного доступа Поскольку записи с двоичным доступом может быть переменной длины, бывает фактически хранятся сведения о размере каждого поля и записи, таким образом, чтобы его можно прочитать успешно. Хороший способ добиться этого является хранение целое число с каждой строкой, чтобы указать длину строки. Ниже приведен пример создания такого файла. ![]() ![]() Type Person LName as String FName as String Age as Integer End Type Sub WriteOneRecord(PRecord as Person) Dim StrSize as Integer ' Write the LName field and indicate the length of LName ' because it is a variable-length string. StrSize = Len(PRecord.LName) Put #1,,StrSize Put #1,,PRecord.LName ' Write the FName field and indicate the length of FName ' because it is a variable-length string. StrSize = Len(PRecord.FName) Put #1,,StrSize Put #1,,PRecord.FName ' Write the Age field - this is type integer so it is not ' necessary to indicate a length. Put #1,,PRecord.Age End Sub Sub WriteBinary() Dim P as Person ' Create a new file and open it for Binary access. Open "BINARY.TXT" For Binary As #1 ' Create and write the first record. P.LName = "Doe" P.FName = "Jane" P.Age = 9 WriteOneRecord P ' Create and write the second record. P.LName = "Thompson" P.FName = "Richard" P.Age = 4 WriteOneRecord P ' Close the file. Close #1 End Sub Чтение файлов, открытых для двоичного доступа Оператор Get считывает число байтов равно байтов, необходимых для переменной, которая будет использоваться. При использовании Get со строкой переменной длины, число байтов, считанных из файла равно текущую длину строки. Временно установить длину строки переменной длины, можно использовать функцию $ STRING для задания переменной равно числу пустые символы или пробелы. В следующем примере считывается файл как тот, созданные с помощью макроса WriteBinary: ![]() ![]() Type Person LName as String FName as String Age as Integer End Type Sub ReadOneRecord(PRecord as Person) Dim StrSize As Integer ' Determine the size of the LName field and read it. Get #1, , StrSize PRecord.LName = String(StrSize," ") Get #1, , PRecord.LName ' Determine the size of the FName field and read it. Get #1, , StrSize PRecord.FName = String(StrSize," ") Get #1, , PRecord.FName ' Read the Age field. Get #1, , PRecord.Age End Sub Sub ReadBinary() Dim P as Person ' Open the file for Binary access. Open "BINARY.TXT" For Binary As #1 ' Read each record in the file and display it in the Debug ' window. Do Until EOF(1) ReadOneRecord P Debug.Print P.LName, P.FName, P.Age Loop ' Close the file. Close #1 End Sub Ключевое сдесь: Хороший способ хранение целое число с каждой строкой, чтобы указать длину строки. Можно использовать ещё одну запись в начале файла и хранить в ней всю инфу типа Count, Length, LengthStart, LengthStart + Length и вывод байтов с позиции (LengthStart TO LengthStart + Length) Наверняка такой велосипед уже есть Есть ещё одно простое и оригинальное решение, использовать встроеный в vb Class PropertyBag http://www.Planet-Source-Code.com/vb/scripts/ShowCode.asp?txtCodeId=52388&lngWId=1 |
Сообщ.
#11
,
|
|
|
Для меня остался непонятным один вопрос - зачем перед дексриптором файла указывается знак "#"? Для того чтобы отличить, например, Print "..." и Print #filehandle? Тогда зачем решетки в других операторах?
|
![]() |
Сообщ.
#12
,
|
|
Цитата DIS @ зачем перед дексриптором файла указывается знак "#"? Это в русском языке существует символ "№"... а в аглицком его роль выполняет символ "#". И вообще называть его "дескриптор" - не очень правильно. Это именно номер. Номер записи в таблице открытых файлов. А вот уже сама запись и есть дескриптор (описАтель)... |
Сообщ.
#13
,
|
|
|
Ребяты, нужен совет.
Я веду свою БД. Обыкновенный двоичный файл, Get #ff/Put #ff... Так вот, переменную, которую я сохраняю - она массив собственного типа. Размерность подошла к 2000. В нутри этого так же есть массивы. Сам файл занимает 9 с лишним мегабайт. Отсюда вытикают последствия - медленно работает. Так вот, собственно, вопрос такой. Как лучше организовать, создать какой-то класс, который будет заниматься тем, что будет создавать буфер сохранений, и по-очереди эти сохранения записывать БД, тем самым разгрузим основную программу. Как бы накидали того, что надо сохранить - а как быстро это сделается - и не волнует никого. Но тогда памяти будет кушать много. Как быть? Использовать уже существующие движки - не вариант. |
Сообщ.
#14
,
|
|
|
Статью осознал, но у меня пустяковая проблема. На форму Form1 вывожу данные, в три этапа. По статье после каждого этапа после вывода через print на форму я записываю все это через print# в файл. Это получилось. Но хотелось бы записать в файл именно выведенную информацию на форме, т. е. форму использовать как некоторую переменную, в которую записана информация и которая записывается в файл. Команда put имя Form1 не понимает
и команда Print #1,Form1 не принимается. Как решить эту задачу? Спасибо. |
![]() |
Сообщ.
#15
,
|
|
Цитата Buka1214 @ Как решить эту задачу? Спасибо. Выводить в соответствующий элемент управления. Судя по соседней теме, ты уже к этому решению пришел. На будущее: одна тема -- один вопрос. Сообщения были разделены в тему "Как создать запись в файл информации, выведенной на форму?" |