Здесь располагается содержимое class "clearfloat" id "рамка"

Курс кружка "Программист"

У р о к и
  1. Этапы решения задач на компьютере. Разработка программы.
  2. *КОНТРОЛЬ*
  3. Понятие алгоритма. Свойства алгоритма.
  4. *КОНТРОЛЬ*
  5. Формы представления алгоритмов. Графический способ записи алгоритмов. Школьный алгоритмический язык.
  6. *КОНТРОЛЬ*
  7. Базовые алгоритмические структуры: базовая структура следование.
  8. *КОНТРОЛЬ*
  9. Базовые алгоритмические структуры: базовая структура ветвление.
  10. *КОНТРОЛЬ*
  11. Базовые алгоритмические структуры: базовая структура ЦИКЛ.
  12. *КОНТРОЛЬ*
  13. Эволюция языков программирования. Классификация языков программирования.
  14. *КОНТРОЛЬ*
  15. Язык Си++. Эволюция языка и его преимущества.
  16. *КОНТРОЛЬ*
  17. Синтаксис языка Си++.
  18. *КОНТРОЛЬ*
  19. Константы и переменные в С++. Преобразование типов данных.
  20. *КОНТРОЛЬ*
  21. Операторы используемые в С++.
  22. *КОНТРОЛЬ*
  23. Некоторые визуальные компоненты С++Builder.
  24. *КОНТРОЛЬ*
    ***Лабораторная работа № 1***
    Создание простого приложения в С++Builder.
  25. Основные константы и математические функции. Команда форматированного вывода строки.
  26. *КОНТРОЛЬ*
    ***Лабораторная работа № 2***
    Создание программы вычисления значения функции.
  27. Условные операторы выбора if.
  28. *КОНТРОЛЬ*
    ***Лабораторная работа № 3***
    Создание программы с разветвленной структурой.
  29. Условный оператор множественного выбора switch. Безусловный переход.
  30. *КОНТРОЛЬ*
    ***Лабораторная работа № 4***
    Создание программы со структурой ВЫБОР.
  31. Оператор цикла for (цикл со счетчиком).
  32. *КОНТРОЛЬ*
    ***Лабораторная работа № 5***
    Создание программы c циклом ДЛЯ.
  33. Операторы цикла с условием. Прерывание цикла.
  34. *КОНТРОЛЬ*
    ***Лабораторная работа № 6***
    Создание программы c циклом ПОКА.
  35. Одномерные массивы. Обработка строк.
  36. *КОНТРОЛЬ*
    ***Лабораторная работа № 7***
    Создание программы обработки строк.
  37. Многомерные массивы.
  38. *КОНТРОЛЬ*
    ***Лабораторная работа № 8***
    Создание программы обработки двумерного массива.
  39. Указатели и ссылки.
  40. *КОНТРОЛЬ*
  41. Функции: объявление, описание и использование.
  42. *КОНТРОЛЬ*
    ***Лабораторная работа № 9***
    Создание и использование функций в C++.
  43. Файлы и потоки. Файловый ввод/вывод с помощью компонентов.
  44. *КОНТРОЛЬ*
    ***Лабораторная работа № 10***
    Работа с файлами с помощью компонентов С++Builder.
  45. Файловый вывод/вывод в двоичном режиме.
  46. *КОНТРОЛЬ*
    ***Лабораторная работа № 11***
    Запись и чтение блоков из двоичного файла (произвольный доступ).

    ***Лабораторная работа № 12***
    Запись, дописывание и чтение потоков из файла.
Дополнения

23. Файловый вывод/вывод в двоичном режиме.

Двоичный файл представляет собой просто последовательность символов, в которой без каких-либо разделителей — пробелов, символов конца строки и т. п. хранятся символы, отображающие самые различные объекты. Они совпадают с тем, как хранятся соответствующие объекты в оперативной памяти. Что именно и в какой последовательности лежит в двоичном файле — должна знать программа.
Двоичные файлы имеют немало преимуществ перед текстовыми при хранении каких-то числовых данных. Операции чтения и записи с такими файлами производятся намного быстрее, чем с текстовыми, поскольку отсутствует необходимость форматирования: перевода в текстовое представление и обратно. Двоичные файлы, как правило, имеют существенно меньший объем, чем аналогичные текстовые файлы. В двоичных файлах вы можете перемещаться в любую позицию и читать или записывать данные в произвольной последовательности, в то время как в текстовых фалах практически всегда производится последовательная обработка информации. Пожалуй, недостаток двоичного файла с точки зрения программиста только один — просматривая его с помощью какого-то текстового редактора, трудно понять, где что в нем находится, и это в ряде случаев затрудняет отладку.
Считывание и запись блоков двоичных данных.
Чтобы считывать и заисывать в файл блоки двоичных данных, можно использовать функции read() и write().
ostream.write(const char *buf, int streamsize num);
записывает num байт данных в связанный с файлом поток из буфера, адресуемого параметром buf.
istream.read(char *buf, streamsize num);
считывает num байт данных из связанного с файлом потока и помещает их в буфер, адресуемый параметром buf.
Достижение конца файла можно контролировать функцией eof(). Функция возвращает true при  достижении конца файла иначе, возвращается значение false.
В C++ можно получать доступ к файлу в произвольном порядке. В этом случае необходимо использовать функции seekg() и  seekp().
istream.seekg(off_type offset, seekdir origin);
перемещает указатель get ввода данных соответствующего файла на offset байт относительно позиции, заданный параметром origin.
ostream.seekp(off_type offset, seekdir origin);
перемещает указатель put вывода данных соответствующего файла на offset байт относительно позиции, заданный параметром origin.
Параметр seekdir определяет точку отсчета в файле, и может принимать следующие значения:
ios::beg – начало файла
ios::cur – текущая позиция
ios::end – конец файла
Для определения текущей позиции указателя в файле используются функции:
tellg() – текущая позиция указателя ввода данных
tellp() – текущая позиция указателя вывода данных.

Запись и чтение в двоичные файлы можно также выполнять функциями fwrite и fread:
#include <stdio.h>
size t  fwrite(const void *ptr,   size t size,   size t n,   FILE  *stream);
size t  fread(void *ptr,   size t  size,   size t n,   FILE  *stream);
В обе функции передается указатель ptr на выводимые или вводимые данные. Параметр size задает размер в байтах передаваемых данных, а параметр n определяет число передаваемых данных. Применение этих функций иллюстрируется приведенным ниже примером.
int  i = 1,   j  = 25,   i1,   j1;
double  a = 25e6,   a1;
char s[10], s1[10];
strcpy(s,"Иванoв");
FILE *F;
// запись в  файл
if   ((F = fopen("Test.dat",   "wb"))   == NULL)
{
ShowMessage("Файл не удается создать");
return;
}
fwrite(&i,sizeof(int),1,F);                                   // запись i
fwrite(&j,sizeof(int),1,F);                                   // запись j
fwrite(&a,sizeof(double),1,F);                         // запись a
fwrite(s,sizeof(char),strlen(s)+1,F);   // запись строки s
fclose(F);
// чтение из файла
if ((F = fopen("Test.dat", "rb")) == NULL)
{
ShowMessage("Файл не удается открыть");
return;
}
fread(&i1,sizeof(int),1,F);                                    // чтение i
fread(&j1,sizeof(int),1,F);                                    // чтение j
fread(&a1,sizeof(double),1,F);                          // чтение a
fread(s1,sizeof(char),strlen(s)+1,F);     // чтение строки s
fclose(F);
В данном примере создается двоичный файл "Test.dat" и в него записывается два целых числа i и j, действительное число a и строка s. Затем этот файл закрывается, открывается для чтения и данные из него читаются в переменные il , jl , al и sl .
В отношении записи и чтения чисел, вероятно, все понятно. А вопрос записи и чтения строк имеет смысл обсудить подробнее.
В приведенном примере запись строки производится оператором
fwrite(s,sizeof(char),strlen(s)+1,F);   // запись строки s

Запись ведется по символам и указано число записываемых символов — strlen(s)+l (единица добавляется на нулевой символ в конце). Читается строка аналогично:
fread(s1,sizeof(char),strlen(s)+1,F);   // чтение строки s
При этом чтение тоже идет по символам и читается strlen(s)+l символов.
Тут внимательный читатель может увидеть некоторую подтасовку. В данном учебном примере мы знаем длину строки, которую записали в файл, и можем прочитать требуемое число символов. Но как быть в реальных задачах, когда мы, скорее всего, не будем знать длину записанной строки? Эту проблему можно решить несколькими путями. Проще всего записывать и читать весь массив символов как единое целое:
fwrite(s,sizeof(s),1,F);
fread(s1,sizeof(s),1,F);
Этот путь простой, но имеет один недостаток: записывается всегда весь массив
символов s, даже если содержащаяся в нем строка много короче размера массива. Приведенные операторы в нашем примере эквивалентны операторам
fwrite(s,sizeof(char)*10,1,F);
fread(s1,sizeof(char)*10,1,F);
Таким образом, при частичном заполнении массива в файле будут храниться лишние байты. Если в файле много строк разной длины, а все они будут храниться как максимальная из них, то размер файла будет значительно больше действительно необходимого.
Другой путь — записывать по-прежнему по символам, но при чтении проверять каждый символ, чтобы при появлении нулевого символа закончить чтение строки. Это может быть реализовано следующим образом:
// запись строки
fwrite(s,sizeof(char),strlen(s)+1,F);
// чтение строки
for(int  ind = 0;   ind <  10;   ind++)
{
fread(s1+ind,sizeof(char),1,F);
if(s1[ind] == '\0') break;
}
Здесь в цикле for читается за раз по одному символу и при обнаружении нулевого символа цикл прерывается. Обратите внимание, что адрес чтения очередного символа в данном случае задается выражением s1+ind. Нельзя было бы вместо этого использовать выражение sl[ind], так как функция fread требует указания именно адреса, а не значения переменной, в которую осуществляется чтение.
Функцию fread в этом примере можно было бы заменить на fgetc, которая читает один символ из потока:
s1[ind] = fgetc(F);
И, наконец, еще один вариант чтения строк неизвестной длины из двоичного файла. Можно перед строкой записывать в файл целое число, равное числу символов в строке. Тогда чтение строки не встретит затруднений:
// запись строки
int  it = strlen(s)+1;
fwrite(&it,sizeof(int),1,F);
fwrite(s,sizeof(char),it,F);

// чтение строки
fread(&it,sizeof(int),1,F);
fread(s1,sizeof(char),it,F);
В приведенных примерах чтение происходило последовательно. Но, работая с двоичными файлами, можно организовать произвольное чтение данных. Для этого служит указатель (курсор) файла, который определяет текущую позицию в файле для чтения и записи. При чтении или записи указатель автоматически смещается на число обработанных байтов. Узнать позицию указателя можно функцией ftell, которая возвращает текущую позицию:
long int  ftell(FILE  *stream);
Изменить позицию указателя можно функцией fseek:
int  fseek(FILE  *stream,   long offset,   int whence);
Эта функция задает сдвиг на число байтов offset относительно точки отсчета, определяемой параметром whence. Если задано значение whence = 1, то offset может быть положительным (сдвиг вперед) или отрицательным (сдвиг назад).
Возможность перемещать указатель особенно полезна в файлах, которые состоят из однородных записей одинакового размера. Например, если в файле записаны только действительные числа типа double, то для того, чтобы прочитать i-ое число, достаточно выполнить операторы
fseek(F,   sizeof(double)*(i-1),   0);
fread(&a,sizeof(double),1,F);
Таким образом можно читать любые записи в любой последовательности.
С помощью перемещения указателя можно редактировать записи в файле. Пусть, например, вы хотите одно из чисел, записанных в файле, изменить, умножив его на 10. Это можно сделать, если открыть файл в режиме чтения и записи (например, "rb+"), установить позицию, соответствующую изменяе мому числу, и выполнить операторы:
fread(&a,sizeof(double),1,F);
a *= 10;
fseek(F,-sizeof(double),1);
fwrite(&a,sizeof(double),1,F);
Первый из этих операторов читает число в переменную a, второй — умножает его на 10. Третий оператор возвращает текущую позицию на одну запись назад, поскольку после выполнения fread позиция сдвинулась вперед. Последний оператор пишет в ту позицию, в которой было прочитано число, новое значение. Ту же задачу можно решить иначе:
long int pos = ftell(F);                                  // запоминание позиции
fread(&a,sizeof(double),1,F);
a *= 10;
fseek(F,pos,0);                                              // восстановление позиции
fwrite(&a,sizeof(double),1,F);
Здесь функция ftell запоминает позицию, из которой читается число, а функция fseek восстанавливает эту позицию перед записью измененного числа.