Re[3]: Работа с файлом
От: LaptevVV Россия  
Дата: 24.12.06 06:46
Оценка: 3 (1)
Здравствуйте, Аноним, Вы писали:

А>Спасибо большое за помощь. Один только вопрос — как мне произвести все те же действия (открыть файл или создать новый, записать в него значение, посмотреть из файла) но только для функции? Если прежде для пробы я проделывал это с переменной а, которой пользователь может давать значение, а потом просматривать из файла, то теперь в файле мне нужно сохранить функцию, в которой создается таблица, и конечно же при повторном запуске программы я смог бы посмотреть отредактированную в прошлый раз таблицу.

Не совсем понял... Под функцией имеется ввиду таблица значений?
Если таблица значений, то это просто массив...
Вот инфа по работе с ООП — в нескольких сообщениях пропишу

Работа с файлами
Стандартные потоки разработаны для концепции командной строки. В настоящее время, когда оконный интерфейс стал повсеместным, стандартные потоки практически не применяются для ввода/вывода информации. Значительно чаще информация организуется в виде файлов, которые тем или иным способом затем обрабатываются программой. Файлы, естественно, связываются с потоками [1 27.8.1]. Для использования файловых потоков необходимо прописать в программе оператор

#include <fstream>

Объекты типа fstream связываются с файлами, которые можно читать, и в которые можно записывать информацию. Так как класс basic_fstream [1-27.8.1.11] является наследником от basic_iostream (см. листинг 10.23), то все операции ввода/вывода, описанные выше для стандартных потоков, работают и с файловыми потоками.
Если нам нужны только входные [1-27.8.1.5] потоки-файлы, достаточно использовать
#include <ifstream>

Для работы с выходными [1-27.8.1.8] файловыми потоками можно задать оператор
#include <ofstream>

Впрочем, <fstream> объединяет и то и другое, поэтому программисты редко используют последние два варианта.
ПРИМЕЧАНИЕ
В некоторых реализациях <fstream> включает объявление <iostream>, поэтому при использовании первого можно не прописывать в программе второго. Однако в системе Visual C++.NET 2003 требует подключать обе библиотеки, если используются оба вида потоков.

Для того, чтобы открыть требуемый файл, нужно просто объявить объект соответствующего типа, указав параметры конструктора, который берет на себя всю работу. По умолчанию файл считается текстовым (см. выше раздел «Текстовые файлы»). Закрывать файл тоже не требуется, так как при уничтожении объекта всю работу выполнит деструктор. Перепишем пример создания и чтения текстового файла number.txt (см. листинг 10.8) с использованием объектно-ориентированной библиотеки.
//Листинг 10.24. Создание текстового файла средствами ОО-библиотеки
#include <fstream>
#include <iostream>            // требуется в Visual C++.NET 2003
#include <ctime>
using namespace std;
int main()
{    srand((unsigned)time(NULL));        // инициализация датчика случайных чисел
 /* открываем выходной текстовый файл для записи */
 {    ofstream strm("c:/textfiles/oonumber.txt");
    for(int i = 0; i < 10; i++)        // выводим 10 чисел 
      strm << rand()%10 << '\n';
 }    // деструктор закроет файл
 /* открываем тот же текстовый файл для чтения */
 {  ifstream strm("c:/textfiles/oonumber.txt");
    char ss[20] = {0};
    while(true)                    
    { strm.getline(ss, 20);             // читаем числа как строки
      if (strm.eof()) break;            // проверяем конец файла
      cout << ss << '\n';            // выводим на экран
    }
 }    // опять деструктор закрывает файл
 return EXIT_SUCCESS;
}

Обратите внимание на внутренние блоки в теле функции main(). Внутри блоков объявлены объекты-потоки: в первом — выходной, во втором — входной. Больше ничего не требуется, так как объявление объекта одновременно и открывает файл и связывает поток с файлом, а при выходе из блока деструктор файл закрывает и разрывает связь. Текст по сравнению с программой из листинга 10.8 здорово упростился! Кроме отсутствия явных операций открытия и закрытия, мы еще не прописываем режима открытия файла — это все реализовано в конструкторе соответствующего класса по умолчанию.
Напишем ту же программу в более традиционном виде — с открытием и закрытием, с проверкой ошибок открытия. Вместо простого вывода на экран содержимого файла просуммируем числа, записанные в файл (листинг 10.25).
//Листинг 10.25. Создание файла и суммирование чисел
#include <fstream>
#include <iostream>                    // требуется в Visual C++.NET 2003
#include <ctime>
using namespace std;
int main()
{    srand((unsigned)time(NULL));            // датчик случайных чисел
    ofstream strm;                            // выходной поток-объект
    strm.open("c:/textfiles/oonumber.txt");    // открываем
    if (strm.is_open())                        // проверка открытия
    { for(int i = 0; i < 10; i++)            // выводим 10 чисел 
        strm << rand()%10 << '\n';
      strm.close();                        // закрываем выходной поток-файл
      // суммирование чисел записанных в файле
      // открываем тот же текстовый файл для чтения 
      ifstream strm("c:/textfiles/oonumber.txt");
      if (strm)                             // проверка открытия    
      { int number, summa = 0, count = 0;
        while(strm >> number)            // ввод числа
        { ++count;                        // подсчет количества
          summa+=number;                // суммирование
        }
        cout << summa << "; " << count;    // вывод результатов
        strm.close();                    // закрываем поток-файл
      }
    }
    return EXIT_SUCCESS;
}

Как видите, практически это не отличается от аналогичной программы, которую мы рассматривали выше (листинг 10.8). Аналогично легко переписывается и программа копирования файлов (листинг 10.26). Если не проверять ошибки, то программа значительно упрощается!
//Листинг 10.26. Копирование файлов
#include <fstream>
#include <ctime>
using namespace std;
// функция копирования потока in в поток out; потоки должны быть открыты
void filecopy (ifstream &in, ofstream &out)
{ char ch;
  while(in.get(ch))        // читать все символы, в том числе пробельные
    out.put(ch); 
}
int main()
{    ifstream instrm ("c:/textfiles/oonumber.txt");
     ofstream outstrm("c:/textfiles/oonumber.new");
     if (instrm) filecopy(instrm, outstrm);        // копирование файлов
 return EXIT_SUCCESS;
}

Заглянув в каталог TextFiles, обнаружим там два файла: исходный oonumber.txt и новый oonumber.new. Простмотрев оба файла в блокноте, можно убедиться в их идентичности.
Необходимо обратить внимание на функцию копирования: параметры должны передаваться по ссылке, так как в процессе операций чтения и записи состояние потоков изменяется. Никакой другой способ передачи параметров не работает.

Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Работа с файлом
От: Аноним  
Дата: 23.12.06 06:48
Оценка:
Здравствуйте, помогите, пожалуйста, реализовать работу с файлом. В этой программе открывается файл, а также сохраняются в него изменения. Но как сделать так, чтоб пользователь мог ввести какие-то данные (хотя бы присвоить значение дополнительной переменной а), которые сохранялись бы в файле и потом их можно было бы посмотреть, открыв из файла? Нужно fy делать в виде структуры? А можно ли будет потом точно также сохранить в файле и прочитать из него созданную из «|» и «-» символов таблицу?


//---------------------------------------------------------------------------

#include <vcl.h>
#include <iostream.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused
int main()


{ FILE *fi, *fo; size_t *fa; void *fy;
if (!(fi=fopen("D:\\1\\FIle.txt", "w+"))) {
cout<<"error";
getch();
return 1;

}
if (!(fo=fopen("D:\\binfile.out", "w+b"))) {
    cout<<"error";
    return 1;
}

 
 FILE *a;   size_t  t=25; size_t r=45;
  fwrite (fy,t, r, fi);

 fread (fy, t, r, fi);



 getch();
 }
//---------------------------------------------------------------------------
Re: Работа с файлом
От: SerhioPro Россия  
Дата: 23.12.06 07:32
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, помогите, пожалуйста, реализовать работу с файлом. В этой программе открывается файл, а также сохраняются в него изменения. Но как сделать так, чтоб пользователь мог ввести какие-то данные (хотя бы присвоить значение дополнительной переменной а), которые сохранялись бы в файле и потом их можно было бы посмотреть, открыв из файла? Нужно fy делать в виде структуры? А можно ли будет потом точно также сохранить в файле и прочитать из него созданную из «|» и «-» символов таблицу?



А>
А>//---------------------------------------------------------------------------

А>#include <vcl.h>
А>#include <iostream.h>
А>#include <conio.h>
А>#include <string.h>
А>#include <stdlib.h>
А>#pragma hdrstop

А>//---------------------------------------------------------------------------

А>#pragma argsused
А>int main()


А>{ FILE *fi, *fo; size_t *fa; void *fy;
А>if (!(fi=fopen("D:\\1\\FIle.txt", "w+"))) {
А>cout<<"error";
А>getch();
А>return 1;

А>}
А>if (!(fo=fopen("D:\\binfile.out", "w+b"))) {
А>    cout<<"error";
А>    return 1;
А>}

 
А> FILE *a;   size_t  t=25; size_t r=45;
А>  fwrite (fy,t, r, fi);

А> fread (fy, t, r, fi);



А> getch();
А> }
А>//---------------------------------------------------------------------------
А>



На мой взгляд, библиотека fstream более благоприятна для работы с файлами, да и потоки там в полной мере реализованы.
Там с выводом таблиц проблем быть не должно, я сам пробовал.
Re: Работа с файлом
От: LaptevVV Россия  
Дата: 23.12.06 07:51
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, помогите, пожалуйста, реализовать работу с файлом. В этой программе открывается файл, а также сохраняются в него изменения. Но как сделать так, чтоб пользователь мог ввести какие-то данные (хотя бы присвоить значение дополнительной переменной а), которые сохранялись бы в файле и потом их можно было бы посмотреть, открыв из файла? Нужно fy делать в виде структуры? А можно ли будет потом точно также сохранить в файле и прочитать из него созданную из «|» и «-» символов таблицу?

А>
А>//---------------------------------------------------------------------------

А>#include <vcl.h>
А>#include <iostream.h>
А>#include <conio.h>
А>#include <string.h>
А>#include <stdlib.h>
А>#pragma hdrstop

А>//---------------------------------------------------------------------------

А>#pragma argsused
А>int main()
А>{ FILE *fi, *fo; size_t *fa; void *fy;
А>if (!(fi=fopen("D:\\1\\FIle.txt", "w+"))) {
А>cout<<"error";
А>getch();
А>return 1;
А>}

А>if (!(fo=fopen("D:\\binfile.out", "w+b"))) {
А>    cout<<"error";
А>    return 1;
А>}
А> FILE *a;   size_t  t=25; size_t r=45;
А>  fwrite (fy,t, r, fi);
А> fread (fy, t, r, fi);
А> getch();
А> }
А>//---------------------------------------------------------------------------
А>

Ну и навертерл ты...
1. Определись, какой файл ты собираешься использовать: текстовый или двоичный...
2. если двоичный, то лучше использовать fread-fwrite
3/ <eath для этих функций должен быть физически выделоен: либо непосредственно объявленный массив, либо — динамический массив. У тебя же fy — только указатель...
3. размер элемента данных лучше задавать как sizeof(тип)
4. Сколько данных у тебя в файле будет?
Почитай вот это:

Открытие и закрытие файлов
Для работы с файлами используются указатели на структуру типа FILE, которая определена в библиотеке <stdio.h>. Объявление файлового потока выглядит так:

FILE *имя;

Имя — это обычное имя в программе на С++, которое обозначает поток, связываемый с файлом на диске. Аналогичный аргумент передается практически всем функциям, выполняющим работу с файлами. Открыть файл и связать поток с ним можно функцией fopen(), имеющей прототип
FILE * fopen(const char *имя_файла, const char *режим);

Имя_файла — это имя файла на диске, оно указывается единственный раз при открытии. Во всех остальных операциях участвует указатель на FILE. Количество открытых одновременно файлов ограничивается константой FOPEN_MAX, определенной в заголовке <stdio.h>.
Режим — это строка, задающая способ дальнейшей обработки файла. Режимы перечислены в табл. 10.4.
Таблица 10.4. Режимы открытия файла
Обозначение Смысл
"r" или "rt" Открыть текстовый файл для чтения. Если файл не обнаружен, функция возвращает ноль (нулевой указатель).
"w" или "wt" Создать текстовый файл для записи. Если файл существует, содержимое файла уничтожается.
"a" или "at" Открыть для добавления строк в конец текстового файла. Если файла нет, он создается.
"r+" или "r+t" Открыть существующий текстовый файл для чтения и записи.
"w+" или "w+t" Открыть новый текстовый файл для чтения и записи. Если файл существует, то его содержимое уничтожается.
"a+" или "a+t" Открыть для чтения и добавления строк в конец текстового файла. Если файла нет, он создается.
"rb" Открыть двоичный файл для чтения. Если файл не обнаружен, функция возвращает ноль (нулевой указатель).
"wb" Создать двоичный файл для записи. Если файл существует, содержимое файла уничтожается.
"ab" Открыть для добавления записей в конец двоичного файла. Если файла нет, он создается.
"r+b" Открыть существующий двоичный файл для чтения и записи.
"w+b" Открыть новый текстовый файл для чтения и записи. Если файл существует, то его содержимое уничтожается.
"a+b" Открыть для чтения и добавления записей в конец двоичного файла. Если файла нет, он создается.
Когда файл открывается в режиме дозаписи («a» или «a+»), любая операция записи выполняется в конец файла. Таким образом, если открыт существующий файл, то все ранее записанные в него данные сохраняются.
Символы t и b, если они задаются, требуется указывать после основных символов r,w,a. В справочной системе Visual C++.NET 2003 приводится следующее замечание о функции fopen():
If t or b is prefixed to the argument, the function fails and returns NULL.
Если t или b стоят перед аргументом, функция завершается неудачей и возвращает NULL.
Нужно отметить, что неправильное написание режима или имени файла никак не диагностируется компилятором при трансляции — это же константы-строки! Ошибки бывают, как правило, совершенно «дурацкие»: пропущена какая-нибудь буква или вместо английской буквы написана русская, не отличающаяся по виду, например «с». В последнем случае текст программы выглядит совершенно правильным, однако работать программа, естественно, не будет — файл просто не откроется. Поэтому нужно обязательно проверять, действительно ли файл открылся (значение указателя не равно нулю).
Пусть на дискете находится текстовый файл Readme.txt. Открыть его для чтения можно таким образом:
FILE *fp = fopen("a:/Readme.txt", "r");

Файл закрывается с помощью функции fclose() с прототипом
int fclose(FILE *имя);

Имя указателя должно совпадать с тем, которое использовалось при открытии. В случае успешного закрытия возвращается 0, иначе — константа EOF. Закрыть открытый выше файл Readme.txt нужно так:
fclose(fp);

Поток по умолчанию буферизован, поэтому закрытие файла освобождает буфер. Однако имеется возможность явно указать освобождение буфера в любой момент работы программы, не закрывая файл. Для этого используется функция
int fflush(FILE *имя);

Аналогично функции закрытия файла в случае успешной записи буфера в файл возвращается ноль, иначе — EOF.
Важнейшей функцией является функция, проверяющая, достигнут ли конец файла. Ее прототип
int feof(FILE *имя);

Очевидно, конец файла может обнаружиться только при чтении из файла. Если в результате очередной операции ввода достигнут конец файла, система устанавливает внутренний индикатор конца файла. Этот индикатор и проверяет данная функция. Если достигнут конец файла, то функция возвращает ненулевое значение, иначе возвращается 0.
С открытием файла связана одна очень распространенная ошибка начинающих программистов, на которую хочется обратить внимание. Предположим, мы обрабатываем текстовые файлы и решили написать функцию, которая открывает файл и обрабатывает ошибки открытия. Определение такой функции может быть таким:
void openfile(FILE *f, char *name)
{  if ((f=fopen(name, “rt”))==NULL)  
       fprintf(stderr, “Не могу открыть файл.\n”);  
}

Вроде бы в определении ничего крамольного не наблюдается. Однако вызов такой функции не принесет желаемых результатов.
FILE *in;
openfile(in, “input.txt”);

Предполагается, что функция откроет файл input.txt, и свяжет его с файловой переменной in. Если файл input.txt находится в текущем каталоге, то никаких сообщений о невозможности открыть файл не будет. Однако работать с файлом будет нельзя – первая же попытка выполнить операцию чтения приведет к аварии программы. А дело в том, что указатель передается по значению, и изменение произойдет только внутри функции openfile(). Никогда не забывайте о том, что файловую переменную, которую требуется открыть или закрыть, нужно передавать в функцию либо по указателю, либо по ссылке.
Двоичные файлы
Двоичные и текстовые файлы — это, как говорят в Одессе, «две большие разницы». Обмен данными между программой и двоичным потоком выполняется без всякого преобразования, поэтому работает быстрее. Двоичный ввод выполняется функцией fread(), имеющей следующий прототип:
size_t fread(void *buffer, size_t size, size_t n, FILE *stream);

Тип size_t обычно определен как unsigned int. Первый параметр часто определяет массив (или указатель на динамический массив), в который будет прочитана информация; третий параметр задает размер одного элемента данных в байтах, а второй — количество читаемых элементов. Четвертый параметр определяет двоичный файл, из которого информация вводится. Общее количество считанных байтов равно size*n. Однако возвращает функция количество корректно прочитанных элементов, а не байтов.
Вывод в двоичный файл выполняется функцией fwrite(), которая имеет совершенно аналогичный прототип:
size_t fwrite(const void *buffer, size_t size, size_t n, FILE *stream);

Функция записывает n элементов размера size в двоичный файл stream из буфера, указатель на который задается в качестве первого аргумента. Общее количество выводимых байтов равно size*n. Однако возвращает функция количество корректно записанных элементов, а не байтов.
В качестве элементов могут использоваться любые переменные любых типов, в том числе и динамические. Даже массив может быть одним-единственным элементом! Рассмотрим несколько простых примеров, аналогичных примерам для текстовых файлов (см. листинги 10.8,10.9). Создадим на диске C: каталог BinFiles и все двоичные файлы будем размещать в нем. Переделаем пример создания файла (листинг 10.12).
//Листинг 10.12. Создание и чтение двоичных файлов
#include <cstdio>
#include <cstdlib>
#include <ctime>
int main()
{    int m[10]={0};
    srand((unsigned)time(NULL));        // инициализация датчика случайных чисел
    FILE *stream;
/* открываем двоичный файл для записи */
    if((stream = fopen("c:/binfiles/number1.bin", "wb" )) == NULL) 
        return 1;                        // ошибка при открытии
/* заполняем массив m числами */
    for(int i = 0; i < 10; i++)
      m[i] = rand()%10;                    // случайные числа от 0 до 9
// заполняем файл number1.bin элементами-числами
    for(int i = 0; i < 10; i++)
      fwrite(&m[i], 1, sizeof(int), stream);    
    fclose(stream);                        // закрываем файл
/* открываем другой файл для записи */
    if((stream = fopen("c:/binfiles/number2.bin", "wb" )) == NULL) 
        return 1;                        // ошибка при открытии
// заполняем файл number2.bin элементом-массивом
    fwrite(m, 1, sizeof(m), stream);    // массив - один элемент
    fclose(stream);                        // закрываем файл
// вывод второго двоичного файла на экран 
// открываем файл для чтения 
    if((stream = fopen("c:/binfiles/number2.bin", "rb" )) == NULL) 
        return 1;                        // ошибка при открытии
    int a = 0;                             // сюда вводим
// читаем второй файл поэлементно
// правильный цикл
    fread(&a, 1, sizeof(int), stream);    // предварительное чтение
    while(!feof(stream))                // пока не конец файла
    { printf("%d\n", a);
      fread(&a, 1, sizeof(int), stream);
    }
    fclose(stream);
// открываем первый файл в режиме чтения
    if((stream = fopen("c:/binfiles/number1.bin", "rb" )) == NULL) 
        return 1;    
    int t[10] = {0};                    // массив для чтения
// читаем первый файл как массив
    fread(t, 1, sizeof(t), stream);        
    for(int i = 0; i < 10; i++)            // выводим поэлементно
        printf("%d\n",t[i]);
    fclose(stream);
char ch = getchar();
return 0;
}

В этой программе сначала создается два двоичных файла: number1.bin и number2.bin. В первый файл целые числа из массива m записываются по одному в цикле. Во второй файл весь массив записывается сразу как один элемент. Затем файлы открываются для чтения. Сначала открывается файл number2.bin (в который мы писали массив целиком), и чтение из него выполняется по одному числу. Проверка конца файла делается так же, как и для текстовых файлов. На экране видно, что чтение выполняется совершенно правильно.
Первый файл number1.bin, который записывался в цикле по одному числу, читается сразу целиком в массив t, а вывод осуществляется по одному числу. И снова мы наблюдаем на экране, что чтение выполнилось совершенно правильно. Такое «смешивание» для двоичных файлов безопасно, так как и в памяти, и на диске размеры данных равны sizeof(тип)*n, где n — количество элементов, участвующих в обмене.
Теперь добавим в конец этого примера строки, выполняющие суммирование чисел, записанных в файл number1.bin.
// суммирование чисел записанных в файле
    if((stream = fopen("c:/binfiles/number1.bin", "rb" )) == NULL) 
        return 1;                        // ошибка при открытии
    // читаем числа по одному из файла и считаем 
    int number, summa = 0, count = 0;
    fread(&number, 1, sizeof(int), stream);
    while(!feof(stream))
    { printf("%d\n", number);
      ++count;
      summa+=number;
      fread(&number, 1, sizeof(int), stream);
    }
    printf("%d %d\n", summa, count);
    fclose(stream);

Как видим, этот текст отличается от приведенного выше для текстовых файлов только режимом открытия и функцией ввода данных.
Так как функции посимвольного ввода/вывода fgetc() и fputc() фактически не выполняют никакого преобразования информации, то копирование двоичных файлов можно делать точно так же, как и текстовых — посимвольно. Используем функцию filecopy(), представленную в листинге 10.9.
// копирование файлов
FILE *in, *out;
if((in = fopen("c:/binfiles/number1.bin", "rb" )) == NULL) 
{    printf ("Error input file!"); return 1;        // ошибка при открытии
}
if((out = fopen("c:/binfiles/number1.new", "wb" )) == NULL) 
{    printf ("Error output file!");    return 1;    // ошибка при открытии
}
filecopy(in, out);                    // копирование                            
fclose(in); 
fclose(out);

Соответственно и для объединения файлов можно использовать ту же функцию — все определяется режимом открытия файла.
// дозапись нового файла в конец старого
if((out = fopen("c:/binfiles/number1.bin", "ab" )) == NULL) 
{    printf ("Error output file!");    return 1;    }
if((in = fopen("c:/binfiles/number1.new", "rb" )) == NULL) 
{    printf ("Error input file!");    return 1;    }
filecopy(in, out);                    // объединение – дозапись!
fclose(in);
fclose(out);

Для проверки правильности объединения выведем содержимое файла на экран. Используем вторую форму проверки окончания файла — внутри цикла:
//  вывод нового файла на экран для проверки
if((stream = fopen("c:/binfiles/number1.bin", "rb" )) == NULL) 
    return 1;    
while(true)
{ fread(&a, 1, sizeof(int), stream);
  if (feof(stream)) break;
  printf("%d\n", a);
}
fclose(stream);

Размеры объектов в файле
Как мы уже знаем (см. гл. 1), размеры классов и структур в памяти зависят от выравнивания. Рассмотрим тот же вопрос с точки зрения записи в двоичный файл. Напишем простую программу (листинг 10.13), в которой просто выведем в двоичный файл несколько структур в двух режимах: с выравниванием по байту и без.
//Листинг 10.13. Размеры объектов на диске
#include <cstdio>
#include <iostream>
using namespace std;
//#pragma pack(1)                        // выранивание по байту
int main()
{    FILE *f;
    class Empty {};                        // пустой класс
    Empty t;
    if((f = fopen("c:/binfiles/binempty.bin", "wb" )) == NULL) 
        return 1;                        // ошибка при открытии
    fwrite(&t, 1, sizeof(t), f);            // пишем пустой класс
    fclose(f);
    struct BinNotPack1                    // неупакованная структура
    {    double a;  char ch; int b; };
    BinNotPack1 A = { 1.0, 'a', 1};
    cout << sizeof(A) << endl;            // размер = 16
    if((f = fopen("c:/binfiles/binnotpack1.bin", "wb" )) == NULL) 
        return 1;                        // ошибка при открытии
    fwrite(&A, 1, sizeof(A), f);            // на диске - 16
    fclose(f);
    struct BinNotPack2                    // неупакованная структура
    {    int b; double a; char ch;  };
    BinNotPack2 B = { 1, 1.0,'a'};
    cout << sizeof(B) << endl;            // размер = 24
    if((f = fopen("c:/binfiles/binnotpack2.bin", "wb" )) == NULL) 
        return 1;                        // ошибка при открытии
    fwrite(&B, 1, sizeof(B), f);            // на диске - 24
    fclose(f);
}

Эта простая программа записывает в наш каталог BinFiles три файла: binempty.bin, binnotpack1.bin и binnotpack2.bin. В первый файл записывается «пустой» класс, а во второй и третий – специально не выровненные структуры. Как выясняется, на диск записывается точно столько же байт, сколько структура занимает в памяти. В системе Visual C++.NET 2003 при отсутствии директивы выравнивания размеры переменных Empty t, BinNotPack1 A, BinNotPack2 B равны 1, 16 и 24 байта соответственно. Ровно столько же места они занимают и на диске — каждая в своем файле. Если же прописать директиву выравнивания
#pragma pack(1),

то размеры структур станут равны 13 — столько же и записывается в файлы.
В системе Borland C++ Builder 6 наблюдается аналогичная картина. При отсутствии выравнивания на диск записывается 8, 16 и 24 байта . При наличии директивы выравнивания на диск записывается столько же байт, как и в системе Visual C++ — 1,13 и 13 байт.
Нужно упомянуть об одной важной детали, связанной с двоичным вводом/выводом. Программа, которая считывает информацию из двоичного файла, должна «знать» размер и структуру считываемой информации. При записи в файл туда попадает только та информация, которая явно задана в операторах вывода. Никаких данных о типе выводимого значения на диске нет, если только мы сами их туда не запишем. Поэтому очень просто совершить ошибку: записать в файл число одного типа, а прочитать записанные байты в переменную другого типа. Например, int и float в системе Visual C++.NET 2003 занимают в памяти одинаковое количество байтов — четыре. Поэтому в приведенных выше примерах (листинг 10.12) можно было бы записать на диск массив дробных чисел типа float, а считывать его как массив целых чисел. Никаких сообщений об ошибках, естественно, не выдается; программа может даже работать, но результат, как вы понимаете, будет абсолютно неверным.
Поэтому функции ввода/вывода обычно разрабатываются «парами»: одна для записи в файл, другая — для чтения из файла.

Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Работа с файлом
От: LaptevVV Россия  
Дата: 23.12.06 07:54
Оценка:
Здравствуйте, Аноним, Вы писали:

Не обратил внимания — у тебя ж подключено iostream.h В этой библиотеке нет функций fread-fwrite. Они есть в библиотеке cstdio. Вместо iostream.h нужно использовать fstream (без .h)
Там свои формы работы с файлами...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: Работа с файлом
От: Аноним  
Дата: 24.12.06 03:39
Оценка:
Здравствуйте, LaptevVV.

Спасибо большое за помощь. Один только вопрос — как мне произвести все те же действия (открыть файл или создать новый, записать в него значение, посмотреть из файла) но только для функции? Если прежде для пробы я проделывал это с переменной а, которой пользователь может давать значение, а потом просматривать из файла, то теперь в файле мне нужно сохранить функцию, в которой создается таблица, и конечно же при повторном запуске программы я смог бы посмотреть отредактированную в прошлый раз таблицу.
Re[3]: Работа с файлом
От: LaptevVV Россия  
Дата: 24.12.06 06:50
Оценка:
Здравствуйте, Аноним, Вы писали:

Режимы открытия потоков (файлов)
Как и потоки библиотеки <cstdio>, объектно-ориентированные файловые потоки можно открывать в различных режимах [1-27.4.2.1.4]. Однако режимы — это не текстовая строка, как в библиотеке <cstdio>, а целая статическая константа размером в один бит (как и состояния потока, режимы открытия часто называют флагами). Режимы открытия описаны в табл. 10.7, а соответствие объектно-ориентированных и не объектно-ориентированных режимов приведено в табл. 10.8.

Таблица 10.7. Режимы открытия потоков
Режим Описание
in Открытие потока для чтения (умолчание для ifstream)
out Открытие потока для записи (умолчание для ofstream)
trunc Удаление старого содержимого файла (умолчание для ofstream)
app Открытие потока для записи в конец файла
ate Открытие потока (чтение и/или запись) и позиционирование в конец файла
binary Открывает поток в двоичном режиме (по умолчанию – текстовый)
ПРИМЕЧАНИЕ
В некоторых системах (в частности, в Visual C++.NET 2003) имеются дополнительные режимы вроде nocreate или noreplace, однако они не являются стандартными и поэтому не рассматриваются.

Поскольку режимы представляют собой биты, то их можно объединять битовой операцией operator|, например

std::ios::in|std::ios::binary

или
std::ios::in|std::ios::out|std::ios::ate

В конструкторах и методах open() присутствует второй параметр, определяющий режим открытия потока. Открытие файлового потока для чтения/записи не зависит от типа объекта, объявляемого в программе — этот тип определяет только режим открытия по умолчанию при отсутствии второго аргумента. Это означает, что поток типа istream вполне можно открывать и для записи тоже, а поток ofstream — для чтения. Однако операции, разрешенные для объявленного объекта, определяются классом потока данных.

Таблица 10.8. Соответствие режимов открытия
Флаги-режимы открытия Описание Режим открытия <cstdio>
in Чтение (файл должен существовать) “r”
out Стирание и запись (файл создается, если его нет) “w”
out|trunc Стирание и запись (файл создается, если его нет) “w”
app Дозапись (файл создается, если его нет) “a”
out|app Дозапись (файл создается, если его нет) “a”
in|out Чтение и запись (файл должен существовать) “r+”
in|out|trunc Стирание, чтение и запись (файл создается, если его нет) “w+”
Другие комбинации, не указанные в таблице — запрещены. Однако в любую из указанных комбинаций можно добавить флаг binary и/или ate, например
std::ios::in|std::ios::out|std::ios::binary|std::ios::ate

Такое сочетание флагов означает открытие файлового потока в двоичном режиме для чтения/записи с первоначальным позиционированием в конец файла.
Для того, чтобы добавить к существующему файлу oonumber.new существующий файл oonumber.txt, достаточно в программе копирования файлов (листинг 10.26) изменить всего одну строчку — объявление выходного файлового потока:
ofstream outstrm("c:/textfiles/oonumber.new", std::ios::app);

Все остальное остается без изменений. После работы можно в блокноте открыть файл oonumber.new и убедиться, что он содержит две одинаковые последовательности чисел, записанные в файле oonumber.txt.
Двоичные файлы[/c]
Вывод в двоичные файлы обычно выполняется методом write(), который мы уже рассматривали выше при выводе символов и строк. Все же обычно с его помощью выводят как раз не символы, а данные других типов. Метод имеет прототип
ostream& write(const char *str, streamsize count);

Метод записывает count символов символьного массива str в поток данных. Тип streamsize [1-27.4.1] обычно представляет собой знаковую версию size_t. Никакие символы-ограничители не влияют на вывод. Возвращает ссылку на поток, поэтому после операции можно проверить состояние потока.
Метод делает то же самое, что и функция fwrite() библиотеки <cstdio>. Используя преобразование указателей, можно вывести в выходной двоичный поток значение переменной любого типа, например
int i = 5;
to.write((char *)&i, sizeof(i));
TMoney d(200.56);
to.write(reinterpret_cast<char *>(&d), sizeof(TMoney));

Можно вывести и массив, например
long t[10];
to.write((char *)&t[0], sizeof(t));

Ввод из двоичных файловых потоков делается методом read(), который имеет такой же прототип
istream& read(char *str, streamsize count);

Метод читает count символов в символьный массив str. Размер символьного массива должен быть достаточен, чтобы вместить count символов. Возвращает ссылку на поток, поэтому после операции можно проверить состояние потока. Никакие символы-разделители и символы-завершители не влияют на ввод. Если обнаружен конец файла, то устанавливаются флаги eofbit и failbit.
Метод работает так же, как и соответствующая функция fread() из библиотеки <cstdio>. Используя преобразование указателей, можно ввести из входного двоичного потока значение переменной любого типа, например
int ii; TMoney dd;
from.read((char *)&ii, sizeof(ii));
from.read(reinterpret_cast<char *>(&dd), sizeof(TMoney));
long t[10];
from.read((char *)&t[0], sizeof(t));

Существует еще один метод ввода, имеющий прототип [1-27.6.1.3]
streamsize readsome(char *str, streamsize count);

Метод работает аналогично методу read(), но возвращает не ссылку на поток, а количество введенных символов.
Теперь легко переписать примеры (см. листинг 10.12) обработки двоичных файлов. В первом примере мы создаем два двоичных файла из одного массива (листинг 10.27).
//Листинг 10.27. Создание и обработка двоичных файлов
#include <fstream>
#include <iostream>
#include <ctime>
using namespace std;
int main()
{    int m[10]={0};
    srand((unsigned)time(NULL));        // инициализация датчика случайных чисел
   /* заполняем массив m числами */
    for(int i = 0; i < 10; i++)
    { m[i] = rand()%10;
      cout << m[i] << ' ';            // контрольный вывод
    }
    cout << '\n';
     /* открываем файл для записи */
    ofstream outstrm ("c:/binfiles/oonumber1.bin", std::ios::binary);
    if(outstrm.is_open())
    { for(int i = 0; i < 10; i++)    // выводим массив в файл поэлементно
        outstrm.write((char *)&m[i], sizeof(int));    
      outstrm.close();
    }
    /* открываем другой файл для записи */
    outstrm.open("c:/binfiles/oonumber2.bin", std::ios::binary);
    if(outstrm.is_open()) 
    { outstrm.write((char*)m, sizeof(m));    // выводим массив в файл 
      outstrm.close();
    }
// вывод двоичного файла на экран 
    // открываем второй файл для чтения 
    {   ifstream instrm ("c:/binfiles/oonumber2.bin", std::ios::binary);
        int a = 0;
        // читаем числа по одному из файла и выводим 
        while(instrm.read((char *)&a, sizeof(int))) 
            cout << a << ' ';
        cout << '\n';
    }
// открываем первый файл для чтения 
  ifstream instrm ("c:/binfiles/oonumber1.bin", std::ios::binary);
  int t[10] = {0};
  instrm.read((char *)t, sizeof(t));    // чтение файла в массив
  instrm.close();                        // закрываем
  for(int i = 0; i < 10; i++)            
        cout << t[I] << ' ';
  cout << '\n';  
 char ch = getchar();
return 0;
}

В этом примере (как и в примере 10.12) два двоичных файла из одного массива создаются разными способами: в файл oonumber1.bin массив выводится поэлементно, а в файл oonumber2.bin — сразу весь одним оператором. Если мы заглянем в каталог BinFiles, то увидим, что эти два файла имеют одинаковый размер в 40 байт (как и файлы number1.bin и number1.bin, созданные в примере 10.12).
Затем те же файлы открываются как входные, читаются и выводятся на экран. Сначала открывается файл oonumber2.bin (в который мы писали массив целиком), и чтение из него выполняется по одному числу. На экране видно, что чтение выполняется совершенно правильно.
Первый файл oonumber1.bin, который записывался в цикле по одному числу, читается сразу целиком в массив t, одним оператором, и поток тут же закрывается. И снова мы наблюдаем на экране, что чтение выполнилось совершенно правильно.
Копирование и дозапись двоичных файлов можно выполнить той же функцией filecopy(), открыв потоки как двоичные, например
// копирование файлов
{ ifstream instrm ("c:/binfiles/oonumber1.bin", std::ios::binary);
  ofstream outstrm("c:/binfiles/oonumber.new", std::ios::binary);
  if (instrm) filecopy(instrm, outstrm);
}
// дозапись нового файла в конец старого
{ ifstream instrm ("c:/binfiles/oonumber2.bin", std::ios::binary);
  ofstream outstrm("c:/binfiles/oonumber.new",
                    std::ios::app|std::ios::binary);
  if (instrm) filecopy(instrm, outstrm);
}

Как и при обработке файлов функциями библиотеки <cstdio>, разница заключается только в режиме открытия.
[b]ПРИМЕЧАНИЕ

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

Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[4]: Работа с файлом
От: Аноним  
Дата: 25.12.06 00:04
Оценка:
Здравствуйте, LaptevVV. Увы я так и не нашел ответ на свой вопрос... Сохранять массив в файле не составляет труда, а вот с функцией проблема. Наверно проще показать программу, чтоб не ходить вокруг да около.


//---------------------------------------------------------------------------

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <vcl.h>
#include <iostream.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
//---------------------------------------------------------------------------
int tablica (int n,int i, int KF,int VF, int KP, int VP, int KS, int VS, char TF, char TP, char TS)
{for ( i=1; i<=5; i++)
   {cout<<"|";
   for (int j=0; j<=51;j++)
    cout<< "-"; cout<<"|"<<endl;

   if (i==1)
   cout<<"|     Name   "<<"|"<<" Tipe |"<<" Quantity "<<"|"<<" Weight 1 detail (g) |"<<endl;

   if (i==2)
   {cout<<"|   Flanec   "<<"|  "<<TF<<"   |   ";
   if(KF>99)
   cout<<KF<<"   ";
   else if(KF>9)
   cout<<KF<<"    ";
   else
   cout<<KF<<"     ";
   cout<<" |          ";

   if (VF>99999)
   cout<<VF<<"     |"<<endl;
   else if (VF>9999)
   cout<<VF<<"      |"<<endl;
   else if (VF>999)
   cout<<VF<<"       |"<<endl;
   else if (VF>99)
   cout<<VF<<"        |"<<endl;
   else if (VF>9)
   cout<<VF<<"         |"<<endl;
   else
   cout<<VF<<"          |"<<endl;}
 //-----------------------------------------------------------------
   if (i==3)
   {cout<<"| Perehodnik "<<"|  "<<TP<<"   |   ";
   if(KP>99)
   cout<<KP<<"   ";
   else if(KP>9)
   cout<<KP<<"    ";
   else
   cout<<KP<<"     ";
   cout<<" |          ";

   if (VP>99999)
   cout<<VP<<"     |"<<endl;
   else if (VP>9999)
   cout<<VP<<"      |"<<endl;
   else if (VP>999)
   cout<<VP<<"       |"<<endl;
   else if (VP>99)
   cout<<VP<<"        |"<<endl;
   else if (VP>9)
   cout<<VP<<"         |"<<endl;
   else
   cout<<VP<<"          |"<<endl;}
  //-----------------------------------------------------------------------

     if (i==4)
   {cout<<"| Stanina    "<<"|  "<<TS<<"   |   ";
   if(KS>99)
   cout<<KS<<"   ";
   else if(KS>9)
   cout<<KS<<"    ";
   else
   cout<<KS<<"     ";
   cout<<" |          ";

   if (VS>99999)
   cout<<VS<<"     |"<<endl;
   else if (VS>9999)
   cout<<VS<<"      |"<<endl;
   else if (VS>999)
   cout<<VS<<"       |"<<endl;
   else if (VS>99)
   cout<<VS<<"        |"<<endl;
   else if (VS>9)
   cout<<VS<<"         |"<<endl;
   else
   cout<<VS<<"          |"<<endl;}}}

//---------------------------------------------------------------------------



В ней я создаю свою таблицу.



void main()

{ int n,i,f, r, a, KF=3,VF=450, KP=8, VP=74, KS=1, VS=117050; //Таблица обладает начальными значениями
 char TF='Z', TP='P', TS='O';

 FILE *stream;
hy:
cout<<"1. Create a new file\n";
cout<<"2. Open file\n";
int t;
cin>>t;
if (t==1)
{stream = fopen("D:/1/FILE.bin", "wb" );  //Здесь мне нужно записать в файл исходную таблицу
 r=tablica(n,i, KF,VF, KP, VP, KS, VS, TF, TP, TS); 
fwrite(&r, 1, sizeof(int), stream);}  //Но как это сделать с целой функцией я не знаю.

else
if (t==2)  //Тут я могу открыть из файла уже записанную туда таблицу
{stream = fopen("D:/1/FILE.bin", "r+b" );
fread(&r, 1, sizeof(a), stream);
tablica(n,i, KF,VF, KP, VP, KS, VS, TF, TP, TS);
 cout<<endl;}
else
{cout<<"Error\n";
goto hy;}


cout<<"Hotite li otredaktirovat tablicu? Da(1)/ Net(2)\n"; //Далее я редактриую исходную таблицу
  cin>>a;
  if (a==1)
  {cout<<"Vvedite kolichestvo Flanca\n";
  cin>>KF;
  cout<<"Vvedite ves 1 flanca\n";
  cin>>VF;
  point1:
  cout<<"Vvedite Tip:\n"<<"Z - zaimstvovanny\n";
  cout<<"P - pokupnoy\n"<<"O - originalny\n";
  cin>>TF;
  if (TF!='Z'&& TF!='O' && TF!='P')
  {cout<<"Takogo tipa net\n";
  goto point1; }

  cout<<"Vvedite kolichestvo Perehodnikov\n";
  cin>>KP;
  cout<<"Vvedite ves 1 perehodnika\n";
  cin>>VP;
  point2:
  cout<<"Vvedite Tip:\n"<<"Z - zaimstvovanny\n";
  cout<<"P - pokupnoy\n"<<"O - originalny\n";
  cin>>TP;
  if (TP!='Z'&& TP!='O' && TP!='P')
  {cout<<"Takogo tipa net\n";
  goto point2; }

cout<<"Vvedite kolichestvo staniny\n";
  cin>>KS;
  cout<<"Vvedite ves 1 staniny\n";
  cin>>VS;
  point3:
  cout<<"Vvedite Tip:\n"<<"Z - zaimstvovanny\n";
  cout<<"P - pokupnoy\n"<<"O - originalny\n";
  cin>>TS;
  if (TS!='Z'&& TS!='O' && TS!='P')
  {cout<<"Takogo tipa net\n";
  goto point3; }

   r=tablica(n,i, KF,VF, KP, VP, KS, VS, TF, TP, TS);//И здесь должен сохранить в файл новую таблицу 
  fwrite(&r, 1, sizeof(int), stream);

fclose(stream);
 }
  //----------------------------------------------------------------------------
 tablica (n,i, KF,VF, KP, VP, KS, VS, TF, TP, TS); //Кроме того могу таблицу отсортировать
 cout<<"Hotite otsortirovat? Da(1)/Net(2)\n"; //Наверно все это тоже надо выразить еще одной функцией,
 cin>>a;                                      //Чтоб можно было как она есть записать в файл
 if (a==1)
  {for ( i=1; i<=5; i++)
   {cout<<"|";
   for (int j=0; j<=51;j++)
    cout<< "-"; cout<<"|"<<endl;

   if (i==1)
   cout<<"|     Name   "<<"|"<<" Tipe |"<<" Quantity "<<"|"<<" Weight 1 detail (g) |"<<endl;

   if (i==4)
   {cout<<"|   Flanec   "<<"|  "<<TF<<"   |   ";
   if(KF>99)
   cout<<KF<<"   ";
   else if(KF>9)
   cout<<KF<<"    ";
   else
   cout<<KF<<"     ";
   cout<<" |          ";

   if (VF>99999)
   cout<<VF<<"     |"<<endl;
   else if (VF>9999)
   cout<<VF<<"      |"<<endl;
   else if (VF>999)
   cout<<VF<<"       |"<<endl;
   else if (VF>99)
   cout<<VF<<"        |"<<endl;
   else if (VF>9)
   cout<<VF<<"         |"<<endl;
   else
   cout<<VF<<"          |"<<endl;}

  //-----------------------------------------------------------------
   if (i==2)
   {cout<<"| Perehodnik "<<"|  "<<TP<<"   |   ";
   if(KP>99)
   cout<<KP<<"   ";
   else if(KP>9)
   cout<<KP<<"    ";
   else
   cout<<KP<<"     ";
   cout<<" |          ";

   if (VP>99999)
   cout<<VP<<"     |"<<endl;
   else if (VP>9999)
   cout<<VP<<"      |"<<endl;
   else if (VP>999)
   cout<<VP<<"       |"<<endl;
   else if (VP>99)
   cout<<VP<<"        |"<<endl;
   else if (VP>9)
   cout<<VP<<"         |"<<endl;
   else
   cout<<VP<<"          |"<<endl;}
  //-----------------------------------------------------------------------

     if (i==3)
   {cout<<"| Stanina    "<<"|  "<<TS<<"   |   ";
   if(KS>99)
   cout<<KS<<"   ";
   else if(KS>9)
   cout<<KS<<"    ";
   else
   cout<<KS<<"     ";
   cout<<" |          ";

   if (VS>99999)
   cout<<VS<<"     |"<<endl;
   else if (VS>9999)
   cout<<VS<<"      |"<<endl;
   else if (VS>999)
   cout<<VS<<"       |"<<endl;
   else if (VS>99)
   cout<<VS<<"        |"<<endl;
   else if (VS>9)
   cout<<VS<<"         |"<<endl;
   else
   cout<<VS<<"          |"<<endl;}}
 }

  getch();
}
//------------------------------------------------------------------------


Вот так... Подскажите, пожалуйста. Знаю, программа громоздкая, но я еще не опытный программист. Я вообще только учусь...
Re[5]: Работа с файлом
От: LaptevVV Россия  
Дата: 25.12.06 06:28
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, LaptevVV. Увы я так и не нашел ответ на свой вопрос... Сохранять массив в файле не составляет труда, а вот с функцией проблема. Наверно проще показать программу, чтоб не ходить вокруг да около.



А>
А>//---------------------------------------------------------------------------

А>#include <cstdio> 
А>#include <cstdlib>
А>#include <ctime>
А>#include <fstream>       // зачем обе библиотеки?
А>#include <vcl.h>      а это зачем? 
А>#include <iostream.h>
А>#include <conio.h>
А>#include <string.h>
А>#include <stdlib.h>      Это тож самое, что и <cstdlib>
А>//---------------------------------------------------------------------------
А>int tablica (int n,int i, int KF,int VF, int KP, int VP, int KS, int VS, char TF, char TP, char TS)
А>{ 
А>}
А>

Ты вот в этой функции вместо cout напиши вывод в файловый поток... Тока в текстовый...
Если уж тебе так нужно прям таблицу нарисованную хранить...
Хотя я не совсем понимаю, зачем... Прекрасно можно хранить в двичном виде — не такая уж и большая таблица... А при необходимости корректировать — считываешь, меняешь и опять записываешь... вывод непосредственно таблицы — только на экран и печать...
А>cout<<"Hotite li otredaktirovat tablicu? Da(1)/ Net(2)\n"; //Далее я редактриую исходную таблицу
  cin>>>a;

А вот это — сделай отдельной функцией...
А> tablica (n,i, KF,VF, KP, VP, KS, VS, TF, TP, TS); //Кроме того могу таблицу отсортировать
А> cout<<"Hotite otsortirovat? Da(1)/Net(2)\n"; //Наверно все это тоже надо выразить еще одной функцией,
 cin>>>a;                                      //Чтоб можно было как она есть записать в файл
А>

Ну так и ради бога... Зачем опять шапка и все колонки в явном виде прописывать? Не понимаю...
Делай отдельную функцию... Сколько строчек в таблице-то? Одна запись какую структуру имеет? — ответь сначала себе на эти вопросы...

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

Удачи — задавай вопросы...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Работа с файлом
От: LaptevVV Россия  
Дата: 25.12.06 06:45
Оценка:
Здравствуйте, Аноним, Вы писали:

Вот еще посмотри — небольшой пример, мож поможет...

Применение форматирования
Рассмотрим применение средств форматирования для создания форматированного отчета о наличии товаров. Допустим, у нас есть подготовленный в текстовом редакторе файл товаров, в котором одна запись занимает 2 строки: на первой строке записано название товара, на второй — количество и цена.
Пусть файл записан на дискете с именем tovar.dat.. Требуется записать новый файл-ведомость, который потом можно будет выводить на принтер. В одной строке файла 5 полей:
1. Номер по порядку, ширина поля — 3 символа;
2. Название товара — 40 символов;
3. Цена — 7 символов; два знака после запятой;
4. Количество — 6 символов, целое число;
5. Стоимость = количество  цена — 12 символов; 2 знака после запятой.
Поля разделяются символом «|» (вертикальная черта). Название нужно выравнивать влево, и если оно больше 40 символов, то его надо обрезать. Числа нужно выравнивать вправо. Числа-деньги выводить с фиксированной точкой с двумя знаками после точки. Десятичная система установлена по умолчанию, а ширину поля приходится задавать для каждого поля (для каждой операции вывода) заново. После всех записей нужно вывести итоговую сумму. Записывать файл будем тоже на дискету (листинг 10.31).

Листинг 10.31. Форматирование ведомости
#include <fstream>
#include <iomanip>
#include <string>
using namespace std;
int main()
{    struct Tovar
    {    string name;                    // наименование товара
        unsigned int HowMany;            // количество
        double Price;                    // цена
    };
    Tovar tmp;
    ifstream inf("a:/tovar.dat");        // исходный файл
    ofstream to ("a:/summa.dat");        // файл-ведомость
int i = 1;    double Summa = 0;
// чтение первой записи
    getline(inf, tmp.name); 
    inf >> tmp.HowMany; inf >> tmp.Price; inf.ignore();
while(!inf.eof())                        // пока не конец файла
{    to << right << setw(3) << i++ << '|';                        
     to << left << setw(40) << tmp.name.substr(0,40) << '|';
     to.precision(2);                                     
     to << right << fixed 
       << setw(6) <<  tmp.HowMany << '|' 
        << setw(7) <<  tmp.Price << '|'
        << setw(12) << tmp.Price*tmp.HowMany << '|'
        << endl;
    getline(inf, tmp.name);
    inf >> tmp.HowMany; inf >> tmp.Price; inf.ignore();
};
    to << setw(72) << Summa << endl;
    return EXIT_SUCCESS;
}

После чтения чисел потребовалось вставить ignore() для пропуска символа конца строки, иначе ввод работал неправильно. Максимально используются манипуляторы, что существенно повышает ясность программы.
Если исходный файл tovar.dat содержал следующие данные,
Авторучки перьевые
1031 257.50
Авторучки шариковые
2143 6.50
Лампы настольные люминисцентные белые
300 350
Папки для бумаг
10677 12.67

то результирующий файл summa.dat будет выглядеть так:

 1|Авторучки перьевые                      |  1031| 257.50|   265482.50|
 2|Авторучки шариковые                     |  2143|   6.50|    13929.50|
 3|Лампы настольные люминисцентные белые   |   300| 350.00|   105000.00|
 4|Папки для бумаг                         | 10677|  12.67|   135277.59|

Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[6]: Работа с файлом
От: Аноним  
Дата: 25.12.06 06:47
Оценка:
Здравствуйте, LaptevVV. Если я в функции все cout заменю на strm, как же таблица будет выводиться-то при вызове ее?
Покажите, пожалуйста, на этом кусочке, как именно мне нужно выводить таблицу из файла? r я присвоил функцию чуть выше, но это все равно не правильно...

else
if (t==2)
{ifstream strm("D:/1/FILE.txt", "r+b" );
fread(&r, 1, sizeof(a), stream);
tablica(n,i, KF,VF, KP, VP, KS, VS, TF, TP, TS);
cout<<endl;}
Re[7]: Работа с файлом
От: LaptevVV Россия  
Дата: 25.12.06 06:50
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, LaptevVV. Если я в функции все cout заменю на strm, как же таблица будет выводиться-то при вызове ее?

А>Покажите, пожалуйста, на этом кусочке, как именно мне нужно выводить таблицу из файла? r я присвоил функцию чуть выше, но это все равно не правильно...
А>else
А>if (t==2)
А>{ifstream strm("D:/1/FILE.txt", "r+b" );
А>fread(&r, 1, sizeof(a), stream);
А>tablica(n,i, KF,VF, KP, VP, KS, VS, TF, TP, TS);
А> cout<<endl;}

1. таблица состоит из одной строки?
2. Какая структура одной строки? Какие числа там сидят и в каком порядке? Имеется ввиду тип в С++, а не смысл чисел...
Пока на эти вопросы не ответишь — с места не сдвинешься...
Мне ответь — подскажу чего-нить...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[8]: Работа с файлом
От: Аноним  
Дата: 26.12.06 05:49
Оценка:
Здравствуйте, LaptevVV.

Дело обстоит так…
В таблице четыре строки, первая из них под заголовки столбцов.
В каждой строке по четыре клетки. Каждая первая – заголовок строки. В каждой второй по переменной типа char, все остальные целочисленные.

Мне сегодня посоветовали в файл запихнуть не функцию, а структуру с данными таблицы. Но проблема та же – теперь я не знаю как с помощью fwrite записать в файл структуру.
Покажите на этом простом примере

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <iostream.h>
#include <conio.h>
//---------------------------------------------------------------------------

#pragma argsused
int main()
{
 struct max{int a1; int b1;};
 max a, b;
int r;
 FILE *stream;
  cout<<"1|2";
  cin>>r;
    if (r==1)

 {  stream = fopen("D:/1/FILE.bin", "wb");
 cout<<"VVedi\n";
  cin>>a.a1;
  cin>>b.b1;
  fwrite(&a,&b, 1, sizeof(int), stream); //ему не нравится в эта строка
   fclose(stream);
   }

  else if(r==2)
  {
  stream = fopen("D:/1/FILE.bin", "r+b");
  fread(a,b, 1, sizeof(int), stream);  //ну и здесь наверно как-то иначе данные
  cout<<a.a1<<"   "<<b.b1;            //нужно извлекать
  fclose(stream);}
  getch();
  }
//---------------------------------------------------------------------------
Re[9]: Работа с файлом
От: LaptevVV Россия  
Дата: 26.12.06 07:21
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, LaptevVV.


А>Дело обстоит так…

А>В таблице четыре строки, первая из них под заголовки столбцов.
А>В каждой строке по четыре клетки. Каждая первая – заголовок строки. В каждой второй по переменной типа char, все остальные целочисленные.

А>Мне сегодня посоветовали в файл запихнуть не функцию, а структуру с данными таблицы. Но проблема та же – теперь я не знаю как с помощью fwrite записать в файл структуру.

Брось маяться фигней и записывать в файл заголовки... В файле пусть зранится только три строки по 4 элемента.
struct OneRowTable
{ char ch;
  int A;
  int B;
  int C;
};

OneRowTable t[3];
// как-то ты их заполняешь - хотя б как ты показывал тут в длинных программах с вопросами к пользователю... :)
FILE f;
fwrite(t, sizeof(t), 1, f); // ввсе три строки там будут...
// или так
fwrite(&t[0], sizeof(OneRowTable), 1, f); 
fwrite(&t[1], sizeof(OneRowTable), 1, f); 
fwrite(&t[2], sizeof(OneRowTable), 1, f);

Если вопросы есть — задавай...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: Работа с файлом
От: Аноним  
Дата: 26.12.06 07:27
Оценка:
Здравствуйте, LaptevVV.

Вот почти готовая программа, но есть одно НО




//---------------------------------------------------------------------------

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <vcl.h>
#include <iostream.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
//---------------------------------------------------------------------------

 #pragma argsused
int tablica (int n,int i, int KF,int VF, int KP, int VP, int KS, int VS, char TF, char TP, char TS)
{for ( i=1; i<=5; i++)
   {cout<<"|";
   for (int j=0; j<=51;j++)
    cout<< "-"; cout<<"|"<<endl;

   if (i==1)
   cout<<"|     Name   "<<"|"<<" Tipe |"<<" Quantity "<<"|"<<" Weight 1 detail (g) |"<<endl;

   if (i==2)
   {cout<<"|   Flanec   "<<"|  "<<TF<<"   |   ";
   if(KF>99)
   cout<<KF<<"   ";
   else if(KF>9)
   cout<<KF<<"    ";
   else
   cout<<KF<<"     ";
   cout<<" |          ";

   if (VF>99999)
   cout<<VF<<"     |"<<endl;
   else if (VF>9999)
   cout<<VF<<"      |"<<endl;
   else if (VF>999)
   cout<<VF<<"       |"<<endl;
   else if (VF>99)
   cout<<VF<<"        |"<<endl;
   else if (VF>9)
   cout<<VF<<"         |"<<endl;
   else
   cout<<VF<<"          |"<<endl;}
 //-----------------------------------------------------------------
   if (i==3)
   {cout<<"| Perehodnik "<<"|  "<<TP<<"   |   ";
   if(KP>99)
   cout<<KP<<"   ";
   else if(KP>9)
   cout<<KP<<"    ";
   else
   cout<<KP<<"     ";
   cout<<" |          ";

   if (VP>99999)
   cout<<VP<<"     |"<<endl;
   else if (VP>9999)
   cout<<VP<<"      |"<<endl;
   else if (VP>999)
   cout<<VP<<"       |"<<endl;
   else if (VP>99)
   cout<<VP<<"        |"<<endl;
   else if (VP>9)
   cout<<VP<<"         |"<<endl;
   else
   cout<<VP<<"          |"<<endl;}
  //-----------------------------------------------------------------------

     if (i==4)
   {cout<<"| Stanina    "<<"|  "<<TS<<"   |   ";
   if(KS>99)
   cout<<KS<<"   ";
   else if(KS>9)
   cout<<KS<<"    ";
   else
   cout<<KS<<"     ";
   cout<<" |          ";

   if (VS>99999)
   cout<<VS<<"     |"<<endl;
   else if (VS>9999)
   cout<<VS<<"      |"<<endl;
   else if (VS>999)
   cout<<VS<<"       |"<<endl;
   else if (VS>99)
   cout<<VS<<"        |"<<endl;
   else if (VS>9)
   cout<<VS<<"         |"<<endl;
   else
   cout<<VS<<"          |"<<endl;}}}

//---------------------------------------------------------------------------

void main()

{  struct {int KF,VF, KP, VP, KS, VS; char TF, TP, TS;} max;

int n,i,f, r, a;


 FILE *stream;
hy:
cout<<"1. Create a new file\n";
cout<<"2. Open file\n";
int t;
cin>>t;
if (t==1)
{stream = fopen("D:/1/FILE.bin", "wb" );

 max.KF=3,max.VF=450, max.KP=8, max.VP=74, max.KS=1, max.VS=117050;  max.TF='Z', max.TP='P', max.TS='O';
 r=tablica(n,i, max.KF,max.VF, max.KP, max.VP, max.KS, max.VS, max.TF, max.TP, max.TS);
fwrite(&max, 1, sizeof(max), stream);}

else
if (t==2)
{stream = fopen("D:/1/FILE.bin", "r+b" );
fread(&max, 1, sizeof(max), stream);
tablica(n,i, max.KF,max.VF, max.KP, max.VP, max.KS, max.VS, max.TF, max.TP, max.TS);
 cout<<endl;}
else
{cout<<"Error\n";
goto hy;}


cout<<"Hotite li otredaktirovat tablicu? Da(1)/ Net(2)\n";
  cin>>a;
  if (a==1)
  {cout<<"Vvedite kolichestvo Flanca\n";
  cin>>max.KF;
  cout<<"Vvedite ves 1 flanca\n";
  cin>>max.VF;
  point1:
  cout<<"Vvedite Tip:\n"<<"Z - zaimstvovanny\n";
  cout<<"P - pokupnoy\n"<<"O - originalny\n";
  cin>>max.TF;
  if (max.TF!='Z'&& max.TF!='O' && max.TF!='P')
  {cout<<"Takogo tipa net\n";
  goto point1; }

  cout<<"Vvedite kolichestvo Perehodnikov\n";
  cin>>max.KP;
  cout<<"Vvedite ves 1 perehodnika\n";
  cin>>max.VP;
  point2:
  cout<<"Vvedite Tip:\n"<<"Z - zaimstvovanny\n";
  cout<<"P - pokupnoy\n"<<"O - originalny\n";
  cin>>max.TP;
  if (max.TP!='Z'&& max.TP!='O' && max.TP!='P')
  {cout<<"Takogo tipa net\n";
  goto point2; }

cout<<"Vvedite kolichestvo staniny\n";
  cin>>max.KS;
  cout<<"Vvedite ves 1 staniny\n";
  cin>>max.VS;
  point3:
  cout<<"Vvedite Tip:\n"<<"Z - zaimstvovanny\n";
  cout<<"P - pokupnoy\n"<<"O - originalny\n";
  cin>>max.TS;
  if (max.TS!='Z'&& max.TS!='O' && max.TS!='P')
  {cout<<"Takogo tipa net\n";
  goto point3; }

   tablica(n,i, max.KF,max.VF, max.KP, max.VP, max.KS, max.VS, max.TF, max.TP, max.TS);
  fwrite(&max, 1, sizeof(max), stream); //ВОТ ТУТ ОН ДОЛЖЕН СОХРАНЯТЬ ВСЕ НОВЫЕ ДАННЫЕ
                                        //НО ОН ЭТО НЕ ДЕЛАЕТ. ПОЧЕМУ?
fclose(stream);
 stream = fopen("D:/1/FILE.bin", "r+b" );
 fread(&max, 1, sizeof(max), stream);
tablica(n,i, max.KF,max.VF, max.KP, max.VP, max.KS, max.VS, max.TF, max.TP, max.TS);
 fclose(stream);

 }  getch(); }
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.