<?xml version='1.0' encoding="utf-8"?>
      <rss version='2.0'>
      <channel>
      <title>Форум на Исходниках.RU</title>
      <link>https://forum.sources.ru</link>
      <description>Форум на Исходниках.RU</description>
      <generator>Форум на Исходниках.RU</generator>
  	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=39292&amp;view=findpost&amp;p=254586</guid>
        <pubDate>Sat, 29 Nov 2003 18:37:20 +0000</pubDate>
        <title>Работа с файлами</title>
        <link>https://forum.sources.ru/index.php?showtopic=39292&amp;view=findpost&amp;p=254586</link>
        <description><![CDATA[Song: &copy; Vit  ;) <br>
<br>
Текстовый файл отличается тем что он разбит на разные по длине строки, отделенные символами #13#10.<br>
<br>
<strong class='tag-b'>Сперва, Вам придётся освоить (вспомнить) древний паскалевский способ:</strong><br>
<br>
Для доступа к текстовым файлам используется переменная типа TextFile. До сих пор не совсем понимаю что это такое физически - что-то типа &quot;внутреннего&quot; паскалевского Handle на файл.<br>
Итак чтобы ассоциировать файл на диске с переменной надо проделать следующие опрерации:<br>
<br>
1) Определяем файловую переменную:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Var F:TextFile;</div></ol></div></div></div></div><script>preloadCodeButtons('1');</script><br>
<br>
2) Ассоциируем ее:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">AssignFile(F, &#39;c:\MyFile.txt&#39;);</div></ol></div></div></div></div><br>
<br>
3) Теперь надо этот файл открыть, есть 3 варианта:<br>
  - файла нет или он должен быть перезаписан, открытие для записи:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">ReWrite(f)</div></ol></div></div></div></div><br>
<br>
  - файл есть и его надо сбросить на чтение (с начала файла)<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Reset(f)</div></ol></div></div></div></div><br>
<br>
  - файл есть и его надо открыть для дозаписи строк в конец<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Append(f)</div></ol></div></div></div></div><br>
<br>
Как видите не хватает очень полезных функций таких как открытия файла для чтения с произвольной строки и для записи в файл произвольной строки. Но надо учесть, что так как длины строк разные, не существует никакого способа узнать физическое место начала например 1000 строки, не прочитав всю тысячу строк. Для записи ситуация еще сложнее - вставить строку означает перезаписать всю информацию после этой строки заново. Таким образом варианты только следующие:<br>
- Перезаписать весть файл<br>
- Читать с первой строки<br>
- Дописать что-то в конец<br>
- Читать и писать файл целиком (см. ниже работу через TStrings)<br>
4) В конце работы открытый файл нужно закрыть:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">CloseFile(f);</div></ol></div></div></div></div><br>
<br>
Очень часто работу этих процедур объединяют для придания допоолнительного полезного эффекта. Ну, например, процедура Reset() сбрасывает файл на чтение. А, если файла нет? Правильно, тогда его надо открыть для записи. Для определения существует файл или нет в Паскале существует переменная IOresult, которая возвращает резльтат от выполнения <strong class='tag-b'>последней операции ввода/вывода</strong>. В случае успеха операции она возвращает <strong class='tag-b'>0</strong> или код ошибки в случае ошибки. Например, рассмотрим пример программы, которая будет открывать файл для дополнения и создавать, если он отстутствует:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">...</div><div class="code_line">&nbsp;AssignFile(F,&#39;my_file.txt&#39;);</div><div class="code_line">{$I-}</div><div class="code_line">&nbsp;Append(f);</div><div class="code_line">&nbsp;IF IOresult&#60;&#62;0 then ReWrite(f);</div><div class="code_line">{$I+}</div><div class="code_line">&nbsp;try</div><div class="code_line">&nbsp; WriteLn(f,&#39;Дополняем текстовый файл my_file.txt&#39;);</div><div class="code_line">&nbsp;finally</div><div class="code_line">&nbsp; CloseFile(F);</div><div class="code_line">&nbsp;end;</div><div class="code_line">...</div></ol></div></div></div></div><br>
<br>
Здесь строка собственно записывается в WriteLn(). <br>
<br>
Запись целой строки:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">WriteLn(f,s);</div></ol></div></div></div></div><br>
<br>
WriteLn - это сокращение от &quot;Write Line&quot;. Т.е. записать строку. Строка будет заканчиваться в файле байтами #13#10. А теперь как записать без этих байт:<br>
<br>
Запись кусочка строки(те следующая операция записи будет произведена в ту же строку):<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Write(f,s);</div></ol></div></div></div></div><br>
<br>
Если переменная s содержит больше 255 символов (т.е. является длинной строкой), то таким способом ни фига не запишится, в файл вместо строки попадут 4 байта указателя на нее. Надо делать так:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">WriteLn(f,Pointer(s)^);</div></ol></div></div></div></div><br>
<br>
Также в данном примере Вы видите возможно неизвестные для Вас {&#036;I-} и {&#036;I+}. Это директивы компилятора. {&#036;I-} - означает что компилятор должен вместо этой директивы включить в объектный код программы, код, который будет подавлять сообщение об ошибке, которое неизбежно возникнет при выполнении процедуры Append() в случает отсутствия файла. {&#036;I+} - выключение этого режима.<br>
<br>
Вверху мы рассмотрели пример записи строки S (WriteLn), а теперь прочитаем её.<br>
Пусть у нас есть строковая переменная S для чтения строки из файла<br>
Чтение предварительно открытого файла:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">ReadLn(f, s)</div></ol></div></div></div></div> - будет прочитанна текущая строка и позиция чтения переведена на следующую позицию.<br>
<br>
А как прочитать весь файл?<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;... // Откроем файл для чтения</div><div class="code_line">While not Eof(f) Do </div><div class="code_line"> Begin</div><div class="code_line">   ReadLn(f, s);</div><div class="code_line">   {здесь делаем ?то-то с про?итанной строкой}</div><div class="code_line">&nbsp;End;</div><div class="code_line">... // Закроем файл</div></ol></div></div></div></div><br>
<br>
Хорошо, а если файл несколько метров есть ли способ поставить какой-нибудь ProgressBar или Gauge чтобы показывал сколько считанно? Есть, но не совсем прямой - не забыли, сколько строк в файле заранее мы не знаем, узнать можно только прочитав его весь, но показательный пример мы все-таки сделаем:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Var  Canceled:Boolean;</div><div class="code_line">&nbsp;</div><div class="code_line">Function GetFileSize(FIleName: String): Integer;</div><div class="code_line"> Var f: File of Byte;</div><div class="code_line">Begin</div><div class="code_line"> try</div><div class="code_line">   AssignFile(f, FileName);</div><div class="code_line">   Reset(f);</div><div class="code_line">   Result:=FileSize(F);</div><div class="code_line">   CloseFile(f);</div><div class="code_line"> except</div><div class="code_line">   Result:=-1;</div><div class="code_line"> end;</div><div class="code_line">End;</div><div class="code_line">&nbsp;</div><div class="code_line">Procedure ReadMyFile;</div><div class="code_line">Var i, j: Integer;</div><div class="code_line">Begin</div><div class="code_line">  ProgressBar1.Max:=GetFileSize(&#39;c:\MyFile.txt&#39;);</div><div class="code_line">  ProgressBar1.position:=0;</div><div class="code_line">  AssignFile(f,&#39;c:\MyFile.txt&#39;);</div><div class="code_line">  Canceled:=False;</div><div class="code_line">  Reset(f);</div><div class="code_line">&nbsp; try</div><div class="code_line">   i:=0;j:=0;</div><div class="code_line">   While not Eof(f) do</div><div class="code_line">     Begin</div><div class="code_line">      Inc(j);</div><div class="code_line">      ReadLn(f,s);</div><div class="code_line">      i:=i+Length(s)+2;</div><div class="code_line">      IF (j mod 1000)=0 then</div><div class="code_line">       Begin</div><div class="code_line">        ProgressBar1.Position:=i;</div><div class="code_line">        Application.ProcessMessages;</div><div class="code_line">        IF Canceled then Break;</div><div class="code_line">       End;</div><div class="code_line">         {здесь мы ?то-то делаем с прочитанной строкой}</div><div class="code_line">     End;</div><div class="code_line">&nbsp; finally</div><div class="code_line">   CloseFile(f);</div><div class="code_line">&nbsp; end;</div><div class="code_line">End;</div></ol></div></div></div></div><br>
<br>
Теперь комментарии к коду.<br>
1) Функию GetFileSize я рсссмотрю после, она немного по другому подходит к чтению файла (кстати я знаю еще по крайней мере 3 способа ее реализации, поэтому не нужно указывать что это можно сделать легче, быстрее или просто по другому - просто давайте разберем это позже)<br>
2) Переменная i - все время указывает на количество байт которое мы считали - мы определяем длину каждой строки и прибавляем 2 (символы конца строки). Зная длину файла в байтах и сколько байт прочитано можно оценить и прогресс, но<br>
3) Если ставить изменение прогресса после каждой строки, то это очень сильно тормознет процесс. Поэтому вводим переменную j и обновляем прогресс например 1 раз на 1000 прочитанных строк<br>
4) Переменная Canceled - глобальная переменная. Поставьте на форму кнопку, в обработчике нажатия поставьте Canceled:=True; и нажатие кнопки прервет чтение файла. <br>
<br>
<br>
<span class="tag-color tag-color-named" data-value="gray" style="color: gray"><strong class='tag-b'>Добавлено в</strong> <time class="tag-mergetime" datetime="2003-11-29T21:38:17+03:00">29.11.03, 18:38</time></span><br>
Появление Object Pascal дало нам программирование на основе классов, которым намного облегчают жизнь рядовому программисту.<br>
Рассмотрим класс TStrings. Этот класс представляет из себя список. Т.е. попросту говоря, массив строк. TStrings широко используется в различных компонентах для организации списков. Например, наверняка известный Вам компонент TMemo использует в качестве контейнера для строка именно класс TStrings, который организуется в свойстве TMemo.Lines. Тоже самое и для других компонент: TListBox.Items, TComboBox.Items и многих других.<br>
Однако, это абстрактный класс, т.е. он используется <strong class='tag-b'>только для наследования</strong>. Напрямую его создавать нельзя. Потомком от этого класса являются TStringList. С ним-то нам и надо работать.<br>
Сейчас рассмотрим как мы можем использовать TStringList для нашей темы, т.е. для чтения файлов.<br>
У TStrings есть методы записи и чтения в файл - SaveToFile, LoadFromFile. Преимущество - простота использования и довольно высокая скорость, недостаток - читать и писать файл можно только целиком.<br>
Примеры.<br>
1) Загрузка текста из файла в Memo:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Memo1.Lines.LoadFromFile(&#39;c:\MyFile.txt&#39;);</div></ol></div></div></div></div><br>
<br>
2) Сохранение в файл:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Memo1.Lines.SaveToFile(&#39;c:\MyFile.txt&#39;);</div></ol></div></div></div></div><br>
<br>
3) А вот так можно прочитать весь файл в строку:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Function ReadFromFile(FileName:string):string;</div><div class="code_line">begin</div><div class="code_line"> With TStringList.create do</div><div class="code_line">   try</div><div class="code_line">&nbsp;   LoadFromFile(FileName);</div><div class="code_line">&nbsp;   Result:=text;</div><div class="code_line">   finally</div><div class="code_line">    Free;</div><div class="code_line">   end;</div><div class="code_line">end;</div></ol></div></div></div></div><br>
<br>
В данном примере у нас создаётся экземпляр потомка TStrings и в него загружается файл, указанный в параметре процедуры.<br>
У TStrings есть много других дополнительных методов и свойств: (здесь приведены только некоторые из них)<br>
<br>
Свойство <strong class='tag-b'>Strings[индекс]</strong> - возвращает строку списка с индексом, указанным в скобках. Например, <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;ShowMessage(Strings[0]);</div></ol></div></div></div></div> - выведет нам 0-ю строку списка (конечно, если она есть)<br>
<br>
Метод <strong class='tag-b'>Add(строка)</strong> - добавляет в список строку в начало списка.<br>
<br>
Метод <strong class='tag-b'>Insert(индекс,строка)</strong> - вставляет строку после строки, с указанным индексом.<br>
<br>
Метод <strong class='tag-b'>Append(строка)</strong> - добавляет строку в конец списка.<br>
<br>
А сейчас пример программы для добавления строки в существующий (или несуществующий файл) для сравнения, сделанный на &quot;паскалевском&quot; способе и с использованием класса TStrings:<br>
<br>
<strong class='tag-b'>Паскалевский способ:</strong><br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Var ff: TextFile;</div><div class="code_line">...</div><div class="code_line">AssignFile(ff,&#39;my_file.txt&#39;);</div><div class="code_line">{$I-}</div><div class="code_line">Append(ff);</div><div class="code_line">{$I+}</div><div class="code_line">IF IOresult&#60;&#62;0 then ReWrite(ff);</div><div class="code_line">try</div><div class="code_line">&nbsp;WriteLn(ff,&#39;строка для добавления&#39;);</div><div class="code_line">finally</div><div class="code_line">&nbsp;CloseFile(ff);</div><div class="code_line">end;</div></ol></div></div></div></div><br>
<br>
<strong class='tag-b'>Способ с использованием класса TStrings:</strong><br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;With TStringList.Create Do</div><div class="code_line">&nbsp; try</div><div class="code_line">&nbsp;  IF FileExists(&#39;my_file.txt&#39;) then LoadFromFile(&#39;my_file.txt&#39;);</div><div class="code_line">&nbsp;  Append(&#39;строка для добавления&#39;);</div><div class="code_line">&nbsp;  SaveToFile(&#39;my_file.txt&#39;);</div><div class="code_line">&nbsp; finally</div><div class="code_line">&nbsp;  Free;</div><div class="code_line">&nbsp; end;</div></ol></div></div></div></div><br>
<br>
Какой из них выбирать - ваше дело. Однако замечу, что перввым способом можно читать и дополнять файлы практически любого размера, а второй имеет ограничением в использовании пямяти т.к. вся работа со списком происходит в памяти, а не прямиком с файлом, как это сделано в первом варианте.<br>
<br>
<br>
<span class="tag-color tag-color-named" data-value="gray" style="color: gray"><strong class='tag-b'>Добавлено в</strong> <time class="tag-mergetime" datetime="2003-11-29T18:39:07+00:00">29.11.03, 18:39</time></span><br>
Но файлы бывают не только текстовые.<br>
Теперь разберем <strong class='tag-b'>типизированные</strong> файлы. <br>
Типизированный файл - это файл в котором записанны идентичные структуры. Например любой файл можно считать файлом байтов - т.е. можно его читать байт за байтом, можно перейти сразу к любому байту по его номеру, можно сразу узнать сколько байт в файле, можно заменить любой байт на другой не перезаписывая файл. Теперь все это в примерах:<br>
<br>
Объявляем файл байтов:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Var f:file of byte;</div><div class="code_line">    b:Byte;</div></ol></div></div></div></div><br>
<br>
Ассоциируем файловую переменную с физическим файлом:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">AssignFile(f,&#39;c:\myfile.bin&#39;);</div></ol></div></div></div></div><br>
<br>
Теперь мы можем либо перезаписать/создать файл:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">ReWrite(f);</div></ol></div></div></div></div><br>
Либо открыть существующий для чтения и записи:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Reset(f);</div></ol></div></div></div></div><br>
Обратите внимание, что в данном случае функция Reset открывает фал таким образом, что мы можем не только читать файл, но и писать в него в текущую позицию. Это недоступно для текстовых файлов.<br>
<br>
Теперь функции работы с файлом:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Read(f,b); - прочитать 1 байт;</div><div class="code_line">Write(f,b); - записать 1 байт;</div><div class="code_line">Eof(f); - узнать не является ли байт последним;</div><div class="code_line">FileSize(f); - возвращает размер файла (или количество структур, если файл структурированный, см. ниже);</div><div class="code_line">FilePos(f); - возвращает текущую позицию чтения/записи внутри файла.</div><div class="code_line">Seek(f,100); - устанавливает текущее положение считывания/записи на сотый байт.</div></ol></div></div></div></div><br>
<br>
Все эти функции не работают с файлами большими 2 Gb.<br>
После работы файл надо закрыть: <br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">CloseFile(f); </div></ol></div></div></div></div><br>
<br>
<br>
<span class="tag-color tag-color-named" data-value="gray" style="color: gray"><strong class='tag-b'>Добавлено в</strong> <time class="tag-mergetime" datetime="2003-11-29T18:39:49+00:00">29.11.03, 18:39</time></span><br>
<strong class='tag-b'>Структурированные файлы</strong>.<br>
Приведенные выше механизмы будут работать с любым файлом, так как любой файл можно считать файлом байтов. Теперь где это можно использовать? В принципе везде, но в подавляющем большинстве случаев это будет очень неудобно, ведь скорость считывания при чтении по байтам будет на порядки более низкой чем другими способами. Однако в некоторых случаях этот способ может быть очень полезен. Например в программе вам надо заменить 100й байт файла на другой, или прочитать 100й байт файла, например во всяких читерских программах, при взломе и т.п. Здесь такой доступ будет весьма удобен. Гораздо более интересным представляется дальнейшее развитие технологии типизированных файлов (их еще лет 15 назад называли &quot;Файлы прямого доступа&quot;). Представим себе, что файл состоит не из байт а из более сложных структур. Например мы имеем некоторую информацию в виде:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Type MyRec=Record</div><div class="code_line">          Name:string[100];</div><div class="code_line">          Age:byte;</div><div class="code_line">          Membership:Boolean;</div><div class="code_line">          Accounts:array[1..10] of integer;</div><div class="code_line">       End;</div></ol></div></div></div></div><br>
Обратите внимание, что все элементы записи точно типизированны, нет ни длинных строк, ни открытых массивов, ни объектов, другими словами, заранее точно известно сколько именно байт будет занимать переменная этого типа. Объявим переменную этого типа:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Var MyVar:MyRec;</div></ol></div></div></div></div><br>
и файл этого типа:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Var f:File of MyRec;</div></ol></div></div></div></div><br>
Теперь мы можем читать и писать сразу целую структуру, абсолютно так же как и если бы это был один байт:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">AssignFile(f,&#39;c:\MyFile.rec&#39;);</div><div class="code_line">ReWrite(f);</div><div class="code_line">try</div><div class="code_line">&nbsp;With MyVar Do</div><div class="code_line">&nbsp;  Begin</div><div class="code_line">&nbsp;   Name:=&#39;Vitaly&#39;; </div><div class="code_line">&nbsp;   Age:=33;</div><div class="code_line">&nbsp;   Membership:=True;</div><div class="code_line">&nbsp;   Accounts[1]:=12345;</div><div class="code_line">&nbsp;   Accounts[2]:=34985;</div><div class="code_line">&nbsp;  End;</div><div class="code_line">&nbsp;Write(f,MyVar);</div><div class="code_line">finally</div><div class="code_line">&nbsp;Closefile(f);</div><div class="code_line">end;</div></ol></div></div></div></div><br>
<br>
Все остальные функции приведенные в предыдущей статье будут работать так же, только одно отличие - Seek и FileSize оперируют не с количеством байт, а с количеством записей (структур). <br>
<br>
<br>
<span class="tag-color tag-color-named" data-value="gray" style="color: gray"><strong class='tag-b'>Добавлено в</strong> <time class="tag-mergetime" datetime="2003-11-29T18:40:51+00:00">29.11.03, 18:40</time></span><br>
Идем дальше. Есть такое понятие как <strong class='tag-b'>нетипизированный файл</strong>. Это такой файл который содержит разнородные элементы. Например файл EXE - вначале он имеет заголовок, затем двоичный код, в конце какие-то ресурсы. Все части файла имеют разную длину и разную структуру. Тут уже обратится к произвольному элементу сложно, обычно надо вначале узнать где этот элемент находится, подчас это записано в предыдущем куске информации. Работа с такими файлами достаточно сложна и требует вручную разработки алгоритмов его чтения, но в связи гибкостью структуры и компактностью такие файлы составляют большинство. Для работы с нетипизированными файлами используют процедуры BlockRead и BlockWrite, которые позволяют читать/писать произвольное количество байт. Привожу пример пользования этими функциями из справки по Дельфи:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;</div><div class="code_line">Var FromF, ToF: file;</div><div class="code_line">&nbsp;    NumRead, NumWritten: Integer;</div><div class="code_line">&nbsp;    Buf: array[1..2048] of Char;</div><div class="code_line">Begin</div><div class="code_line"> if OpenDialog1.Execute then                               { Display Open dialog box }</div><div class="code_line"> begin</div><div class="code_line">   AssignFile(FromF, OpenDialog1.FileName);</div><div class="code_line">   Reset(FromF, 1); { Record size = 1 }</div><div class="code_line">   if SaveDialog1.Execute then                              { Display Save dialog box}</div><div class="code_line">   begin</div><div class="code_line">     AssignFile(ToF, SaveDialog1.FileName); { Open output file }</div><div class="code_line">     Rewrite(ToF, 1); { Record size = 1 }</div><div class="code_line">     Canvas.TextOut(10, 10, &#39;Copying &#39; + IntToStr(FileSize(FromF))</div><div class="code_line">       + &#39; bytes...&#39;);</div><div class="code_line">     repeat</div><div class="code_line">       BlockRead(FromF, Buf, SizeOf(Buf), NumRead);</div><div class="code_line">       BlockWrite(ToF, Buf, NumRead, NumWritten);</div><div class="code_line">     until (NumRead = 0) or (NumWritten &#60;&#62; NumRead);</div><div class="code_line">       CloseFile(FromF);</div><div class="code_line">       CloseFile(ToF);</div><div class="code_line">   end;</div><div class="code_line"> end;</div><div class="code_line">End;</div></ol></div></div></div></div><br>
<br>
<br>
Этот код копирует из одного файла в другой. Замечания по поводу этого метода работы с файлами - плюсы - очень высокая скорость, особенно если размер буффера увеличить до 64kb-512kb, что позволит считывать файл достаточно большими кусками, чтобы обеспечить отсутствие простоев винчестера, к тому же обеспечивается очень высокая гибкость в работе. Минусы - сложность разработки, необходимость вручную писать все детали механизма чтения/записи и интерпретации данных.<br>
Пожалуй на этом можно было бы и завершить описание работы с файлами средствами Паскаля и файловых переменных, но заглянув в Help Дельфей я обнаружил еще несколько функций достойных упоминания.<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Erase(f) - удаляет файл;</div><div class="code_line">FilePos(f) - возвращает текущую позицию чтения/записи в файл;</div><div class="code_line">Flush(f) - сбрасывает кэшированные файловые операции на диск;</div><div class="code_line">Rename(f, &#39;MyNewFileName.txt&#39;) - переименование файлов;</div><div class="code_line">Truncate(f) - файл обрезается до текущей позиции чтения/записи.</div></ol></div></div></div></div><br>
<br>
<br>
<span class="tag-color tag-color-named" data-value="gray" style="color: gray"><strong class='tag-b'>Добавлено в</strong> <time class="tag-mergetime" datetime="2003-11-29T18:41:19+00:00">29.11.03, 18:41</time></span><br>
Теперь венёмся к работе с файлами чере программирование классов. Но на сей раз более сложный класс - TStream. Он также как и TStrings является абстрактным и для практической с ним работы мы должны использовать его потомков - TFileStream и/или TMemoryStream.<br>
Для работы с файловым потоком Вам надо записать в Uses модули classes, Sysutils (classes - включает в себя собственно определение класса, Sysutils - некоторые константы необходимые для работы).<br>
Вот пример записи/перезаписи файла:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Procedure WriteFileUsingStream(s, FileName:string);</div><div class="code_line">Begin</div><div class="code_line"> With TFileStream.create(FileName, fmCreate or fmOpenWrite) Do</div><div class="code_line">   try</div><div class="code_line">     Write(Pointer(s)^,Length(s));</div><div class="code_line">   finally</div><div class="code_line">     free;</div><div class="code_line">   end;</div><div class="code_line">End;</div></ol></div></div></div></div><br>
<br>
Теперь небольшой разбор:<br>
TFileStream.create - конструктор класса, его вызов требует указания имени файла и опций его открытия, следующие опции определены:<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '> fmCreate = &#036;FFFF;<br>
 fmOpenRead       = &#036;0000;<br>
 fmOpenWrite      = &#036;0001;<br>
 fmOpenReadWrite  = &#036;0002;<br>
 fmShareCompat    = &#036;0000;<br>
 fmShareExclusive = &#036;0010;<br>
 fmShareDenyWrite = &#036;0020;<br>
 fmShareDenyRead  = &#036;0030;<br>
 fmShareDenyNone  = &#036;0040;</div></div><br>
Теперь метод Write - этим методом в файл пишется  любая информация из буфера любого типа, Вам надо указать только буффер и количество записываемых байтов. В данном случае используется переменная типа String в качестве буффера, но так как для длинных строк она представляет собой лишь указатель, то конструкция &quot;pointer(s)^&quot; заставляет обращаться именно к ее содержимому.<br>
А вот этот код демонстрирует чтение файла с использованием файлового потока:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;</div><div class="code_line">Var p: PChar;</div><div class="code_line">Begin</div><div class="code_line"> GetMem(p, 255);</div><div class="code_line"> With TFileStream.create(&#39;c:\myText.txt&#39;, fmOpenReadWrite) Do</div><div class="code_line">   try</div><div class="code_line">     Seek(10,soFromBeginning);</div><div class="code_line">     Read(p^, 254);</div><div class="code_line">   finally</div><div class="code_line">     Free;</div><div class="code_line">   end;</div><div class="code_line"> ShowMessage(p);</div><div class="code_line"> FreeMem(p);</div><div class="code_line">End;</div></ol></div></div></div></div><br>
<br>
И пояснения к коду:<br>
1) Никаких проверок длину файла и его наличие здесь не делается - это демонстрационный код, а не готовая процедура чтения.<br>
2) Файл мы считываем в буффер типа PChar (с тем же успехом можно использовать массив или любой другой контейнер). Для тех кто не помнит - процедуры   GetMem(p, 255) и FreeMem(p) - распределение памяти для строки и освобождение памяти.<br>
3) Метод потока  Seek позволяет установить текущую позицию считывания/записи файла. Первый параметер - номер байта, второй - это от чего считать этот байт (у нас считать от начала файла), возможны варианты:<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '> soFromBeginning - от начала файла<br>
 soFromCurrent - от текущей позиции считывания<br>
 soFromEnd - от конца файла (в этом случае номер байта должен быть отрицательным или равным нулю)</div></div><br>
4) Собственно считывание из потока осуществляется методом read, в котором указывается в качестве параметров буфер в который мы читаем и желаемое количество  байт для чтения. Метод read является функцией, которая возвращает количество байт реально прочитанных из потока.<br>
Заканчивая о файловых потоках хочу упомянуть о методе <br>
<strong class='tag-b'>CopyFrom</strong> который позволяет перекачивать информацию из одного потока в другой и о свойствах:<br>
<strong class='tag-b'>Size</strong> - размер файла<br>
<strong class='tag-b'>Position</strong> - текущая позиция чтения/записи потока<br>
Работа с файловыми потоками весьма быстра, этот класс, являсь классом VCL, в то же время базируется на низкоуровневых функциях Windows, что обеспечивает очень высокую скорость работы и стабильность операций. К тому же многие компоненты и классы VCL поддерживаю прямое чтение и запись с файловыми потоками, что занчительно упрощает работу - например TStringList, TBlobField, TMemoField и другие.<br>
Файловые потоки могут быть рекомендованы к использованию в большинстве  случаев для чтения и записи файлов (за исключением специфических ситуаций, требующих каких-то других подходов), другими словами если вам надо просто записать или считать файл, используйте файловые потоки. <br>
<br>
<br>
<span class="tag-color tag-color-named" data-value="gray" style="color: gray"><strong class='tag-b'>Добавлено в</strong> <time class="tag-mergetime" datetime="2003-11-29T18:41:44+00:00">29.11.03, 18:41</time></span><br>
Еще один способ работы с файлами - это открытие Handle на файл и работу через него. Тут есть 2 варианта - можно использовать функции Дельфи или использовать WinAPI напрямую.<br>
При использовании функций Дельфи можно применять следующие функции:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">FileOpen(FileName, fmOpenWrite or fmShareDenyNone)</div></ol></div></div></div></div> - функция открывает файл и возвращает целое цисло - Handle на файл. Параметры функции - имя файла и тип доступа (все типы доступа я перечислил ранее). Если файл успешно открыт то Handle должен быть положительным цислом, отрицательное число - это код ошибки.<br>
Во всех остальных функциях используется именно значение Handle, возвращаемое этой функцией.<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line"> FileClose(Handle: Integer) - закрывает файл</div><div class="code_line"> FileRead(Handle: Integer; var Buffer; Count: Integer): Integer;</div><div class="code_line"> FileWrite(Handle: Integer; const Buffer; Count: Integer): Integer;</div></ol></div></div></div></div><br>
Эти функции для чтения/записи файла, где Buffer любая переменная достаточного размера для чтения/записи куска информации (обычно типа PChar или массив), <strong class='tag-b'>Count</strong>-количество байт, которое Вы желаете записать/прочитать. Функции возвращают количество байт которые реально были прочитанны или записаны.<br>
Этот тип доступа к файлам применяется весьма редко. Дело в том что он практически дублирует соответствующие функции WinAPI и к тому же обычно работает несколько медленнее, чем например потоки. И все же использование функций FileOpen и FileClose не лишено привлекательности. Наряду с тем что эти функции намного легче в использовании соответствующих функций WinAPI (можете сравнить - FileOpen имеет 2 параметра, cooтветствующая функция WinAPI - CreateFile имеет 7 параметров, большая часть из которых реально требуется лишь в ограниченном числе случаев) этот путь доступа открывает возможность прямого использования всех функций WinAPI про работе с файлами, которые требуют Handle на открытый файл. <br>
<br>
<br>
<span class="tag-color tag-color-named" data-value="gray" style="color: gray"><strong class='tag-b'>Добавлено в</strong> <time class="tag-mergetime" datetime="2003-11-29T18:42:11+00:00">29.11.03, 18:42</time></span><br>
Дельфи предоставляет довольно широкие возможности по файловым операциям без использования механизмов открытия/закрытия файлов.<br>
Вот список наиболее употребимых функций, большинство из которых в фачкстве параметров нуждаются только в имени файла:<br>
<strong class='tag-b'>ChDir(NewCurrentPath: String);</strong> - изменяет текущий каталог (в среде Windows сие конечно не так актуально как в ДОС, но все же), прочитать же текущий каталог можно функцией <strong class='tag-b'>GetCurrentDir</strong>, а текущий каталог для определенного драйва - <strong class='tag-b'>GetDir</strong>.<br>
<strong class='tag-b'>CreateDir(const Dir: String): Boolean;</strong> - создает каталог. При этом предыдущий уровень должен присутствовать. <br>
Если вы хотите сразу создать всю вложенность каталогов используйте функцию <strong class='tag-b'>ForceDirectories(Dir: String): Boolean;</strong> Обе функции возвращают True если каталог создан.<br>
<strong class='tag-b'>DiskFree(Drive: Byte): Int64;</strong> - дает свободное место на диске. Параметер - номер диска 0 = текущий, 1 = A, 2 = B, и так далее<br>
<strong class='tag-b'>DiskSize(Drive: Byte): Int64;</strong> - размер винта. Обратите внимание на то что для результата этой и предыдущей функций абсолютно необходимо использовать переменную типа Int64, иначе макимум того что вы сможете прочитать правильно будет ограничен 2Gb<br>
<strong class='tag-b'>FileExists(Const FileName: string)</strong> - применяется для проверки наличия файла<br>
<strong class='tag-b'>DirectoryExists(Const FileName: String)</strong> - соответственно наличие каталога<br>
<strong class='tag-b'>FileGetAttr(const FileName: string): Integer; и <br>
FileSetAttr(const FileName: string; Attr: Integer): Integer;</strong> - функции для работы с атрибутами файлов. Вот список возможных атрибутов:<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>faReadOnly &#036;00000001 Read-only files<br>
faHidden &#036;00000002 Hidden files<br>
faSysFile &#036;00000004 System files<br>
faVolumeID &#036;00000008 Volume ID files<br>
faDirectory &#036;00000010 Directory files<br>
faArchive &#036;00000020 Archive files<br>
faAnyFile &#036;0000003F Any file</div></div><br>
(Естественно не все атрибуты применимы во всех случаях)<br>
<strong class='tag-b'>RemoveDir(const Dir: string): Boolean;</strong> - удаляет папку(пустую)<br>
<strong class='tag-b'>DeleteFile(const FileName: string): Boolean;</strong> - удаляет файл<br>
<strong class='tag-b'>RenameFile(const OldName, NewName: string) и<br>
ChangeFileName(старое_имя, новое_имя)</strong> - переименовывает файл<br>
<strong class='tag-b'>ChangeFileExt(старое_расширение, новое_расширение)</strong> - переименовывает расширение файла.<br>
<br>
<br>
<span class="tag-color tag-color-named" data-value="gray" style="color: gray"><strong class='tag-b'>Добавлено в</strong> <time class="tag-mergetime" datetime="2003-11-29T18:42:47+00:00">29.11.03, 18:42</time></span><br>
И в заключение пример кода, который собирает информацию о файле:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;</div><div class="code_line">Type TFileInfo=record</div><div class="code_line">                Exists:boolean;//true если файл найден</div><div class="code_line">                Name:String; //имя файла с расширением</div><div class="code_line">                ShortName:String;//DOS 8.3 имя файла</div><div class="code_line">                NameNoExt:String;//имя файла без расширения</div><div class="code_line">                Extension:string;//расширение файла</div><div class="code_line">                AssociatedFile:string;//программа с которой ассоциирован файл</div><div class="code_line">                Path:string;// путь к файлу</div><div class="code_line">                ShortPath:string;// DOS 8.3 путь файла</div><div class="code_line">                Drive:string;// дисковод на котором находится файл</div><div class="code_line">                CreateDate:TDateTime; //время когда файл создан</div><div class="code_line">                Size:Int64;// размер файла (работает для файлов и больше 2Gb)</div><div class="code_line">                Attributes:record //нали?ие/отсутствие системных атрибутов</div><div class="code_line">                             ReadOnly:boolean;</div><div class="code_line">                             Hidden:boolean;</div><div class="code_line">                             System:boolean;</div><div class="code_line">                             Archive:boolean;</div><div class="code_line">                           end;</div><div class="code_line">                ModifyDate:TDateTime; // время последнего изменения файла</div><div class="code_line">                LastAccessDate:TDateTime; // дата последнего открытия файла</div><div class="code_line">              end;</div><div class="code_line">Function ReadFileInfo(FileName:string):TFileInfo;</div><div class="code_line">var ts:TSearchRec;</div><div class="code_line">  Function FileTime2DateTime(FT:_FileTime):TDateTime;</div><div class="code_line">  var FileTime:_SystemTime;</div><div class="code_line">  begin</div><div class="code_line">     FileTimeToLocalFileTime(FT, FT);</div><div class="code_line">     FileTimeToSystemTime(FT,FileTime);</div><div class="code_line">     Result:=EncodeDate(FileTime.wYear, FileTime.wMonth, FileTime.wDay)+</div><div class="code_line">             EncodeTime(FileTime.wHour, FileTime.wMinute, FileTime.wSecond, FileTime.wMilliseconds);</div><div class="code_line">  end;</div><div class="code_line">  Function AssociatedFile(FileExt:string):string;</div><div class="code_line">    var key:string;</div><div class="code_line">  begin</div><div class="code_line">    With TRegistry.create do</div><div class="code_line">      try</div><div class="code_line">        RootKey:=HKEY_CLASSES_ROOT;</div><div class="code_line">        OpenKey(FileExt, false);</div><div class="code_line">        Key:=ReadString(&#39;&#39;);</div><div class="code_line">        CloseKey;</div><div class="code_line">        OpenKey(key+&#39;\Shell\open\command&#39;, false);</div><div class="code_line">        result:=ReadString(&#39;&#39;);</div><div class="code_line">        Closekey;</div><div class="code_line">      finally</div><div class="code_line">        free;</div><div class="code_line">      end</div><div class="code_line">  end;</div><div class="code_line">begin</div><div class="code_line"> Result.Name:=ExtractFileName(FileName);</div><div class="code_line"> Result.Extension:=ExtractFileExt(FileName);</div><div class="code_line"> Result.NameNoExt:=Copy(Result.Name,1,length(Result.Name)-length(Result.Extension));</div><div class="code_line"> Result.Path:=ExtractFilePath(FileName);</div><div class="code_line"> Result.Drive:=ExtractFileDrive(FileName);</div><div class="code_line"> Result.ShortPath:=ExtractShortPathName(ExtractFilePath(FileName));</div><div class="code_line"> if lowercase(Result.Extension)&#60;&#62;&#39;.exe&#39; then Result.AssociatedFile:=AssociatedFile(Result.Extension);</div><div class="code_line"> if FindFirst(FileName, faAnyFile, ts)=0 then</div><div class="code_line">   begin</div><div class="code_line">     Result.Exists:=true;</div><div class="code_line">     Result.CreateDate:=FileDateToDateTime(ts.Time);</div><div class="code_line">     Result.Size:=ts.FindData.nFileSizeHigh*4294967296+ts.FindData.nFileSizeLow;</div><div class="code_line">     Result.Attributes.ReadOnly:=(faReadOnly and ts.Attr)&#62;0;</div><div class="code_line">     Result.Attributes.Hidden:=(faHidden and ts.Attr)&#62;0;</div><div class="code_line">     Result.Attributes.System:=(faSysFile and ts.Attr)&#62;0;</div><div class="code_line">     Result.Attributes.Archive:=(faArchive and ts.Attr)&#62;0;</div><div class="code_line">     Result.ModifyDate:=FileTime2DateTime(ts.FindData.ftLastWriteTime);</div><div class="code_line">     Result.LastAccessDate:=FileTime2DateTime(ts.FindData.ftLastAccessTime);</div><div class="code_line">     Result.ShortName:=ts.FindData.cAlternateFileName;</div><div class="code_line">     Findclose(ts);</div><div class="code_line">   end</div><div class="code_line"> else Result.Exists:=false;</div><div class="code_line">end;</div></ol></div></div></div></div>]]></description>
        <author>Song</author>
        <category>Работа с файлами, форматы файлов и данных</category>
      </item>
	
      </channel>
      </rss>
	