Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Программирование с нуля - это совсем просто! 47) Работа с файлами


Информационный Канал Subscribe.Ru

 
Школа программирования

Программирование с нуля - это совсем просто!

47) Работа с файлами

Я еще придумал, что дальше будет, когда базовый курс закончим. Есть такое замечательное движение разработчиков открытого кода, OSI/OSDL, где энтузиасты из разных стран создают общедоступный софт, свободно доступный всем желающим в исходных текстах. Десятки тысяч таких проектов можно найти в частности на культовом сайте http://sourceforge.net/.

Программисты из России представлены там довольно хило (и это еще мягко сказано), но проектный опыт создания каких-то программных систем во-первых полезен сам по себе, а потом, умение такой проект организовать ценится очень высоко, зарплаты просто заоблачные! Поэтому мы будем тренироваться и в этой области, а кроме того, это потенциально хороший источник дохода - ведь хотя сам софт общедоступен и бесплатен, и пользователи ловятся на халяву, но вот за сопровождение и консультации обычно берутся деньги и немалые. Например, общеизвестный дистрибутив Red Hat Linux можно бесплатно скачать с сайта, все исходные тексты, а вот годовая лицензия на консультации и сопровождение стоит от 30 до 4500 доларов :)


Сейчас я отвечаю на письма от 18-19 января :) поэтому можете прикинуть, когда дойдет очередь до вас, если вы писали. Увы, из-за резкого увеличения числа начавших вновь заниматься (после 44-го выпуска :) писем приходит так много, что обратная связь замедлилась чрезвычайно. В общей очереди также все те находятся, кто занимается на платных курсах бесплатно. Постепенно, надеюсь, очередь до всех дойдет. Но подождать придется и вероятно достаточно долго.

Но так как оставлять без подмоги только начавших заниматься неправильно, напоминаю - во-первых, вы можете обращаться с вопросами к Тане (см. сайт begin.polubomu.ru). Во-вторых помощь вам (по базовому курсу!) окажет также Лена (l.s70@mail.ru), которая совсем недавно начинала вместе со всеми заниматься с нуля, а сейчас уже и меня по гибкости алгоритмического мышления обгоняет. Вежливо, напоминаю, задавайте вопросы, представляетесь, подписываетесь, здороваетесь и прощаетесь.

Это кстати удобно - общаться с теми, кто только что сам прошел путь обучения и очень хорошо представляет, какие там были сложности и проблемы. И поэтому может объяснить более четко, основные проблемные места.

Так что, мне шлете отчеты с выполненными заданиями (напоминаю, на письма типа "сделал все задания, а вот в 20-м не понял, помогите!", но без приложенного кода с решением предыдущих 19-ти я НЕ отвечаю ни при каких обстоятельствах), если сложности какие с пониманием базового курса, обращаетесь по двум вышеприведенным адресам. После этого со сложностями справляетесь и продолжаете заниматься - шлете отчеты, новые сложности - снова к девушкам :) итд.

Ответ, полагаю, вы получите ГОРАЗДО быстрее, нежели от меня (от меня можете и вообще не получить, если в письме нет подписи, а только ник, или в сабже указано не явно "базовый курс" или "школа программирования", а что-то типа "курс американского английского").

* Какие-то у меня проблемы с типом float: когда в типе double выдается 0.7 и 0,4 в аналогичной программе с типом переменной float получается почему-то 0,69999998808 и 0,40000000596.
Кстати, функция abs() не работает с дробными числами, так что мне пришлось использовать fabs().

ЭТо проблемы с числами дробного типа, которые точно не вычисляются. Ошибка в 8-9 знаках конечно не страшны в абсолютном большинстве задач (по-моему, это погрешность в сантиметрах в расстоянии до Луны), однако, как уже говорилось, по этой причине дробные числа нельзя сравнивать точно, на равенство.

x := 0,7;

А в x запишется на самом деле 0,69999998808, и если теперь сделать сравнение

x := 0,7;
if x = 0.7 then

то условие, как это ни удивительно на первый взгляд, не выполнится. Надо как-то так делать:

x := 0,7;
if ( abs(x-0.7) < 0.01 ) then

0.01 - это нужная нам точность расчетов.

PS: Отрисока пикселов в Visual Basic:
Picture1.PSet (х, у), &HFF5500
&HFF5500 – это цвет. а с rbg я не пробовала.
Екатерина

  &HFF5500 - это, я так понимаю, и есть rgb. FF - красный (это
  шестнадцатеричный :) код значения 255), 55 - код синего, 00 -
  зеленого.
  Белый будет наверно &HFFFFFF, черный - &H000000, зеленый -
  &H0000FF.

Немножко ответов. Тормозим из-за множества писем.

27. Списки. Многие схитрили, кто уже Дельфи видимо знал или изучает самостоятельно (правильной, кстати, дорогой идете, товарищи!).

Если оценивать с точки зрения результата, то код хитрецов конечно лучше, но у нас стояла цель изучить взаимодействие списков и средства обработки их содержимого в цикле, построчно. То есть добавить все содержимое, всего списка разом в другой, можно без цикла, одной командой AddStrings(), что безусловно и удобнее, и проще и надежнее. См. далее ответы.

  {Моё замечаение Автосортировка в ListBox1 не нужна (из-за неё
  только код растёт ),
  мы всеравно результата не видем, а ListBox2 сам отсортируе как бы
  мы в него значения
  не заносили. Но это так "лирика". Как говориться "Приказы не
  обсуждаються", поэтому
  не будем менять условия задачи а сделаем так как требуеться, но
  алгоритм будетет не
  самым оптимальным

  вот моё решение если мы не выполняем автосортировку Первого
  списка

  procedure TFMainForm.B_SortAndAddLB2Click(Sender: TObject);
  begin
      LB_2.Items.AddStrings(LB_1.Items); // добавляем первый список ко
  второму,
                                         // во втором списке ключена Автосортировка
  end;
  }

  type
    TFMainForm = class(TForm)
      E_Enter: TEdit;
      L_Enter: TLabel;
      B_AddToLB1: TButton;
      B_ClearLB1: TButton;
      B_SortAndAddLB2: TButton;
      LB_1: TListBox;
      LB_2: TListBox;
      L_LB1: TLabel;
      L_LB2: TLabel;
      procedure B_AddToLB1Click(Sender: TObject);
      procedure B_ClearLB1Click(Sender: TObject);
      procedure B_SortAndAddLB2Click(Sender: TObject);
    private
      { private declarations }
    public
      { public declarations }
    end;

  var
    FMainForm: TFMainForm;

  implementation

  {$R *.dfm}

  procedure TFMainForm.B_AddToLB1Click(Sender: TObject);
  {Добавляем значение к Первому списку}
  begin
    if E_Enter.Text<> ' ' then {Если сторка занчений не пустая}
        LB_1.Items.Append(E_Enter.Text); {То добавим её к списку}
  end;

  procedure TFMainForm.B_ClearLB1Click(Sender: TObject);
  {Очищаем Первый список}
  begin
    LB_1.Items.Clear;
  end;

  procedure TFMainForm.B_SortAndAddLB2Click(Sender: TObject);
  {Здесь мы сортируем Первый список и передаей его во Второй
  список}
  var i:integer;
      TMPStr:TStrings;{Временная переменная для хранения Перового
  списка}
  begin
      {Здесь имеется маленькая загвоздка после того как произойдёт
  Автосортировка
      нельзя будет вернуть исходное содержимое первого списка
  поэтому мы его временно скопируем}
    TMPStr:=TStringList.Create; {Содали временный список}
    TMPStr.AddStrings(LB_1.Items); {копируем в него содержимое нашего
  списка}

    LB_1.Sorted:=true; {Включаем Авторостировку}

    for i:=0 to LB_1.Items.Count-1 do {Начинаем передавать данные из
  первого списка во второй}
       LB_2.Items.Append(LB_1.Items.Strings[i]);{Передаем I Строку первого
  списка}
         {Это не есть лучшее решение, лучше использовать
  LB_2.Items.AddStrings(LB_1.Items); Так быстрее}

    LB_1.Sorted:=false; {Выключаем Автосортировку первого списка}

    {Теперь необходимо привести список к первоначальному виду, для
  чего вернём в него временный список}
    LB_1.Items.Clear; {Очищаем Первый список}
    LB_1.Items.AddStrings(TMPStr);{Копируем из временного списка в
  наш исходный список}
    TMPStr.Free;{Удаляем временный список}
  end;
  Артём

Да, насчет сортировки, я плохо написал ее смысл.

И на Си:

  27. Списки.
  Вроде особых проблем пока со списками не возникло. Вот только
  рассортировать не получается. Я не поняла, это
  какая-то функция отката должна быть, или список просто надо
  запомнить, прежде чем сортировать?
  В общем я думала-думала и ничего не придумала лучше, чем
  немножко схитрить. Не совсем уверена, что это то
  решение, которого Вы ждали, но я добавила третий (не видимый),
  временный список, где храню неотсортированные
  значения:

  #include <vcl.h>
  #pragma hdrstop

  #include "Unit1.h"
  //---------------------------------------------------------------------------
  #pragma package(smart_init)
  #pragma resource "*.dfm"

  TForm1 *Form1;
  //---------------------------------------------------------------------------
  __fastcall TForm1::TForm1(TComponent* Owner)
       : TForm(Owner)
  {
  }
  //---------------------------------------------------------------------------
  //Кнопка "Добавить"
  void __fastcall TForm1::Button1Click(TObject *Sender)
  {
       AnsiString str;
       str=Edit1->Text;
       Form1->ActiveControl= Edit1; //Активно поле ввода
       if (str.Length()<1) return ; //Пустая строка в список не вносится
       ListBox1->Items->Add(str); //Добавляет строку
  }
  //---------------------------------------------------------------------------
  //Кнопка "Очистить"
  void __fastcall TForm1::Button2Click(TObject *Sender)
  {
       ListBox1->Items->Clear(); //Очистка списка 1
       Form1->ActiveControl= Edit1; //Активно поле ввода
  }
  //---------------------------------------------------------------------------
  //Кнопка "Внести"
  void __fastcall TForm1::Button3Click(TObject *Sender)
  {
       ListBox3->Items->Clear(); //Очищаю временный список
       ListBox3->Items->AddStrings(ListBox1->Items); //Список 1 ->
  временный список
       ListBox1->Sorted=true; //Сортировка
       ListBox2->Items->AddStrings(ListBox1->Items); //Список 1 -> Список 2
       ListBox1->Items->Clear(); //Очистка списка 1
       ListBox1->Sorted=false; //Сортировка списка 1 выключена
       ListBox1->Items->AddStrings(ListBox3->Items); //Временный список ->
  Список 1
       Form1->ActiveControl= Edit1; //Активно поле ввода
  }
  Екатерина

Нет, рассортировывать не надо. Это невозможно :) Просто флажок снять.

28-е задание. Заполнить матрицу.

  Randomize
  public mat(100, 100)
  function fill()
  Dim dbBig As Double
  for y = 1 to 100
         for x = 1 to 100
         Mat(x, y) = Rnd - Rnd
         Next x
  Next y
  dbBig = mat(1, 1)
  for y = 1 to 100
       for x = 1 to 100
         if abs(mat(x, y)) > dbBig then
        dbBig = abs(mat(x, y))
        end if
      Next x
  Next y
  Write( dbBig)
  end function
  Максим Кибермаксович

Следующее решение.

  #include <vcl.h>
  #include <math.h>
  #pragma hdrstop
   
  #include "Unit1.h"
  //---------------------------------------------------------------------------
  #pragma package(smart_init)
  #pragma resource "*.dfm"
  TForm1 *Form1;
  //---------------------------------------------------------------------------
  __fastcall TForm1::TForm1(TComponent* Owner)
       : TForm(Owner)
  {
  }
  //---------------------------------------------------------------------------
   
  void __fastcall TForm1::Button1Click(TObject *Sender)
  {
       double z[100][100],zmax;
       int x,y,xmax,ymax;
       zmax=0;
       randomize();
       for (x=0;x<100;x++){
            for (y=0;y<100;y++){
                 z[x][y]=((random(200001)+1)-100001)*1.0/100000;
  //Случайное число от -1 до 1
                 if (zmax<fabs(z[x][y])) { //Проверка на
  максимальность
                      zmax=z[x][y];
                      xmax=x;
                      ymax=y;
                 }
            }
       }
       AnsiString str;
       str="Максимальный элемент матрицы:\n Z["; //Вывод
  результата
       str+=xmax;
       str+=", ";
       str+=ymax;
       str+="]=";
       str+=zmax;
       Label1->Caption=str;
   
   Екатерина

На Паскале:

  program MaxElement;

  {$APPTYPE CONSOLE}

  uses
    SysUtils;

  type TElement=record
          Value:real;
          X:integer;
          Y:integer;
        end;

  var
     Mas:array [1..100,1..100] of real;
     i,j:integer;
     MaxElem:TElement;

  begin
     randomize;
     for i:=1 to 100 do
      for j:=1 to 100 do
            Mas[i,j]:=random*2-1; {Инициализация Массива (Заполняем
  числами от -1 до 1)}
     {Начинаем искать Максимум по модулю}
     MaxElem.Value:=abs(Mas[1,1]); {Берм за максимум первый элемент
  массива}
     MaxElem.X:=1;
     MaxElem.Y:=1;
     {Перебираем все значения массива и сравниваем в поисках
  Макисмума}
     for i:=1 to 100 do
        for j:=1 to 100 do
            if MaxElem.Value<abs(mas[i,j]) then
                begin
                   MaxElem.Value:=abs(Mas[i,j]); {Новый максимум }
                   MaxElem.X:=j; {Столбец}
                   MaxElem.Y:=i; {Строка}
                end;
     {выводим найденный максимум}
     writeln( ' Max is - ' ,MaxElem.Value, ' on row - ' ,MaxElem.Y, ' and column -
  ' ,MaxElem.X);
     Readln;
  end.
  Артём

Артём образцово комментирует!

Кстати, молодцы также те, кто сразу с заданием не справляется, но на мои предложения посмотреть решения готовые других отвечает отказом :) Практика показывает, что 80-90% в конце концов решение находят сами.


Работа с файлами

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

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

Принципы работы с файлами

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

Перед началом работы с некоторым файлом его необходимо открыть. Это означает, что программа сообщает операционной системе, что на некоторое время монопольно захватывает определенный файл для обработки.

1. Открытие файла.

После открытия файла программа может либо считывать с файла данные, либо записывать их в файл, либо выполнять обе эти операции в различной последовательности. Вид конкретного действия с файлами указывается при его открытии. Программисты говорят, что файл открывается на чтение (данные из него будут только считываться, а содержимое не изменится), на запись (старое содержимое файла будет уничтожено и полностью заменится на новое; в некоторых случаях файл может открываться на дозапись, когда новая информация заноситься в его конец , а существующая - остается), и на чтение-запись (допускаются оба вида операций, при этом порядок их следования друг за другом произволен).

Если файл открывается на запись или на чтение-запись, то на всем протяжении работы программы с ним другие приложения не смогут к нему обращаться. Дело в том, что пока программа не прекратит обработку некоторого файла, невозможно предсказать, какое конкретно содержимое будет в нем находиться в ближайшие моменты времени, так как оно может постоянно изменяться. В случае же, когда файл открывается на чтение, его внутренняя структура остается старой. Таким образом открывать один и тот же файл на чтение одновременно могут две или большее количество программ. Все остальные случаи открытия файла подразумевают монопольную работу с ним одной программы.

На самом деле существует возможность одновременного внесения изменений в файл из разных программ . В современных версиях операционных систем Windows существует возможность создания так называемых share-файлов. Хранящиеся в них данные разрешается не только считывать одновременно сразу нескольким программам, но и изменять их. Такие возможности бывают полезны в крупных системах, состоящих из множества одновременно выполняющихся компонентов. Например, если требуется протоколировать их работу, создается один share-файл протокола, в который каждый из компонентов в произвольные моменты времени может записывать текстовый блок, определяющий его состояние. Но такие ситуации достаточно редки. В абсолютном большинстве случаев файл, открытый на запись, доступен только тому приложению, которое его открыло.

2. Обработка файла

Выполняется соответствующая операция считывания из файла определенного количества информации или записывания блока информации в файл.

3. Закрытие файла

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

Закрытие файла имеет и еще одно предназначение. В современных операционных системах процесс ввода-вывода данных часто происходит в так называемых режимах буферизации. Это означает, что данные, которые были записаны в файл с помощью соответствующей команды языка программирования, физически на жесткий диск не попали, а были временно размещены Windows в оперативной памяти, в специальной области, называемой буфером ввода-вывода. Такие буферы предназначены для накапливания в них больших блоков данных, которые затем с помощью одной физической операции записи переносятся на жесткий диск. Такая процедура значительно ускоряет операции файлового обмена - из-за того, что обращение к накопителям на жестких дисках в сотни и тысячи раз медленнее, чем обращение к оперативной памяти. Значительно эффективнее накапливать информацию в объемных буферах, но этот подход таит в себе определенную опасность. Ведь если в системе произойдет сбой, или программа по каким-то причинам забудет закрыть файл, все данные, накопленные в буфере, пропадут, а структура файла на жестком диске может быть испорчена. Поэтому когда выполняется операция закрытия файла, вся информация из системного буфера Windows в обязательном порядке записывается на жесткий диск, вне зависимости от ее объема. Такой процесс принудительно переноса содержимого буфера в физический файл называется вталкиванием (flush). В некоторых языках программирования существуют специальные операторы или команды, позволяющие явно выполнять такое вталкивание по команде из программы, не дожидаясь, пока Windows примет самостоятельное решение о такой операции.

Сначала мы изучим работу с текстовыми файлами. Я пользуюсь в программах исключительно текстовыми файлами уже наверное лет пять. От файлов других форматов удается отказаться в основном в пользу готовых баз данных.

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

Важно! Документы Ворда (.doc) - это НЕ текстовые файлы. Это так называемые двоичные файлы, содержимое которых - не текст.

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

Для работы с текстовым файлом его надо как-то определить в программе. Для этого в Дельфи введен специальный тип TextFile, и необходимо описать переменную этого типа:

var Fo: TextFile;

Fo - это я так люблю называть переменные-файлы. F - file, o - output. Если файл нужен для ввода данных, я называю как-то типа Fi (file input). Вы конечно эту переменную можете как угодно по другому обозвать.

Далее, нам надо связать эту переменную с конкретным файлом. Например, мы хотим создать в каталоге c:\tmp\ текстовый файл teksdta.txt. Обычно текстовые файлы имеют расширение .txt.

Такое связывание переменной Fo с соответствющем ей физическим файлом c:\tmp\teksdta.txt осуществляется командой AssignFile:

  AssignFile( Fo, 'c:\tmp\teksdta.txt' );

Каталог c:\tmp\ конечно должен существовать!

Если не указать полный путь:

  AssignFile( Fo, 'teksdta.txt' );

то файл teksdta.txt создастся в относительном, текущем каталоге, откуда программа будет запущена.

Далее, файл Fo надо открыть на запись. Записывается :) это так:

Rewrite( Fo );

При этом если такого файла не было, он создастся. Если он был, то все его содержимое сотрется.

Теперь в файл можно записать текст. Для этого нужна уже знакомая команда WriteLn, использовавшаяся для вывода строк в консоли. Только первым ее параметром надо указать нашу переменную-файл, Fo, а уже потом следом за ней записываемую в файл строку.

Точно не помню, но по-моему в такой файловой записи нельзя указывать строку-константу, а только переменную.

  var s: string;
  ...
  s := ' Эта строка пойдет в файл! ' ;
  WriteLn(Fo, s); // пишем значение переменной s в файл Fo

По окончании обработки файла его надо закрыть:

CloseFile( Fo );

И все!

Вот например мы запишем в файл 100 строк, каждая из которых будет иметь вид

СТРОКА N 1
СТРОКА N 2
...

  var Fo: TextFile;
      s: string;
  i: Integer;
  begin
  AssignFile( Fo, 'c:\tmp\100str.txt' );
  Rewrite( Fo );

  for i := 1 to 100 do
    begin
    s := ' СТРОКА N ' + IntToStr(i);
    Writeln(Fo,s);
    end;

  CloseFile(Fo);

Считывание из файла тоже немногим сложнее. Оно выполняется с помощью команды ReadLn:

ReadLn(Fi, s);

После ее выполнения в переменную s запишется очередная строка из файла Fi. Этот файл предварительно должен быть открыт на чтение. А делается это командой Reset.

Вот как-то так:

  AssignFile( Fi, 'c:\tmp\100str.txt' );
  Reset( Fi );
  Readln(Fi,s);
  CloseFile(Fi);

Но ведь в файле не одна строка, а много. Как получить доступ к ним всем?

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

  for i := 1 to 100 do
    begin
    Readln(Fo,s);
    end;

то из файла Fo будет последовательно введено 100 строк. При условии, конечно, если эти 100 строк в нем есть.

Но ведь на практике мы почти никогда заранее не знаем, сколько в текстовом файле строк. До каких же пор можно из него считывать данные? Как определить, когда надо остановиться?

В этом поможет специальная функция eof( переменная-файл ). Она принимает значение true, если при выполнении последней команды ReadLn встретился конец файла (была считана последняя в файле строка), и false в противном случае.

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

  AssignFile( Fi, 'c:\tmp\100str.txt' );
  Reset( Fi );
  while not eof( Fi ) do // выполнять цикл, пока НЕ встретился конец
  файла
    begin
    Readln(Fi,s); // ввели в s очередную строку
    ... // обрабатываем содержимое s
    end;
  CloseFile(Fi);


В Си открытие файла и связывание переменной-идентификатором файла с путем к файлу осуществляется одной командой fopen(). Для ее использования надо подключить библитекку stdio.h в начало:

  #include <stdio.h>

Первым параметром fopen() указывается путь к файлу, вторым - способ открытия (на запись, чтение). Специальный тип данных "файл" в Си для хранения идентификатора называется FILE (на самом деле обычный int). Но после него еще звездочку надо указать.

    FILE * fo;
    AnsiString s;

    fo = fopen("c:\\tmp\\100str.txt", "wt");

Обратите внимание, что наклонная черта в записи внутри строк Си должна записываться двумя символами!!!

Вторая строка "wt" означает, что файл открыт на запись (Write) в текстовом виде (Text). Строка "rt" означает соответственно, что на чтение (Read).

Запись строки в файл - функция fputs(). Первый параметр - выводимая строка, второй - идентификатор файла.

fputs("Привет тебе!", fo);

Закрытие файла - fclose(идентификатор-файла);

Как быть, если вместо явной строки мы хотим использовать переменную? Воспользуемся типом AnsiString в Borland C++Builder. Только fputs() этот тип не понимает, поэтому для доступа к нужному представлению строки AnsiString в формате, требуемом fputs(), воспользуемся методом c_str() типа данных AnsiString.

Вот код записи в файл 100 строк:

    FILE * fo;
    AnsiString s;
    int i;

    fo = fopen("c:\\tmp\\100str.txt", "wt");

    for( i = 1; i <= 100; i++ ) {
      s = " СТРОКА N " + IntToStr(i);
      fputs(s.c_str(),fo);
      }

    fclose(fo);

Вот тут:

fputs( s.c_str(), fo );

строка сформирована в переменной s, но при выводе ее значения в файл надо еще дополнительно явно обратиться к методу s.c_str(). Достаточно помнить, собственно, такую запись и все.

Ввод из файла - функция fgets(). Только из-за того, что с типом AnsiString она не работает, придется пользоваться обходными путями.

Мы уже обсуждали, что в Си строки в классическом виде представлены как последовательности, массивы символов. Вот в такой массив символов и надо записать данные из файла. А потом уже перекинуть, например, в переменную типа AnsiString.

Первый параметр функции - буфер, второй - максимальное число символов, которое может быть введено (оно может быть меньшим, ввод остановится, когда встретится символ конца строки). Третий - идентификатор файла.

char buf[100];
fgets(buf, 100, fi);

Загрузить из буфера в переменную нормального строкового вида можно так например:

s.sprintf( "%s",buf );

Эту схему тоже достаточно запомнить.

Проверка конца файла - функция feof(), схожая с паскалевской eof().

Целиком вот так загрузим файл:

    FILE * fi;
    AnsiString s;
    fi = fopen("c:\\tmp\\100str.txt", "rt");

    char buf[100];

    while( ! feof(fi) ) {
      fgets(buf,100,fi);
      s.sprintf( "%s",buf );
      }

    fclose(fi);


В Бейсике я особо не разбирался, поэтому приведу общую схему записи в файл и считывания:

          Dim s As string
          Dim i As Integer

          ' в sw - идентификатор файла для записи
          Dim sw As StreamWriter = File.CreateText("c:\temp\MyTest.txt")

          for i = 1 to 100
              s = " СТРОКА " & i

              sw.WriteLine(s) ' записываем переменную s в файл sw

          Next

          ' закрытие sw:
          sw.Flush()
          sw.Close()

Только насчет правильности записи в файл символов в русской кодировке я не уверен. В VB.NET, скорее всего будет не win1251, а unicode.

          Dim s As string
          Dim i As Integer

          ' sr - файл открыт на чтение
          Dim sr As StreamReader = File.OpenText("c:\temp\MyTest.txt")

          do while sr.Peek() >= 0 ' sr.Peek() возвр. -1 , когда достигнут конец
  файла sr
              s = sr.ReadLine() ' в s занесли очередную строчку из файла
          Loop

          ' закр. файл
          sr.Close()

Надо еще, чтобы были доступны такие объекты, как StreamReader, в начало по аналогии с Си подключить библиотеку ввода-вывода. Делается это такой строчкой:

Imports System.IO

Должна быть самой первой в файле с исходным текстом! Далее пойдет

Public Class Form1

итд.

Задания. Экономно будем расходовать оставшиеся до 50 :)

N 40. На форме размещаем две кнопки, список и поле Memo. В Memo заносим произвольный текст из буфера (руками вставляем), по нажатии на кнопку 1 записываем содержимое Memo в файл (построчно считываем из Memo и построчно записывам в файл). По нажатии на кнопку 2 загружаем из этого файла все строки в список.

N 41. Сортировка файлов. Можно в консоли делать.
В два этапа. Сначала создаем два файла, каждый из которых будет набором случайных значений. Их число выбираем тоже случайно для каждого из файлов, от 100 до 1000 строк. Каждое значение - строка файла представляет собой случайное число от 100 до 999, только в виде строки (IntToStr() используем перед записью числа в файл).
Второй шаг. Создаем новый файл, в который надо записать слитые вместе и отсортированные! значения из двух файлов предыдущего шага.

Если в первом например записаны строки

100
987
543

во втором

789
200
475

то в результирующий файл надо записать

100
200
475
543
789
987

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


(c) 2004-2005 Сергей Бобровский bobrovsky@russianenterprisesolutions.com

Школа программирования с нуля
Все предыдущие выпуски базового курса тут:
http://russianenterprisesolutions.com/sbo/

 

http://subscribe.ru/
http://subscribe.ru/feedback/
Подписан адрес:
Код этой рассылки: comp.soft.prog.prognull
Отписаться

В избранное