Консультация № 178803
01.06.2010, 18:02
41.45 руб.
0 2 1
Здравстуйте уважаемые эксперты! Помогите пожалуйста с написанием консольного приложения, которое осуществляет копирование 10 последних строк из одного файла в другой. Для компиляции буду использовать C++ Builder 6.0. Спасибо большое

Обсуждение

Неизвестный
01.06.2010, 21:19
общий
это ответ
Здравствуйте, Мироненко Николай Николаевич.

Предлагаю Вам два варианта программы — (1) с потоками и (2) файловый ввод/вывод в стиле C. Обе программы построены по одной схеме: если заданы параметры в командной строке (см. комментарии в коде), то имена входного и результирующего файлов берутся из нее, иначе - запрашиваются у пользователя. Исходный файл читается построчно с сохранением 10 последних прочитанных строк в циклическом буфере. Это позволяет избежать ненужного копирования и к концу мы получаем в буфере 10 последних строк файла. Затем буфер просто сбрасывается в выходной файл.

Ниже приведено решение с использованием потоков:
Код:
// Написать консольное приложение, которое осуществляет копирование 
// 10 последних строк из одного файла в другой.

#include <fstream>
#include <iostream>
using namespace std;

const int nLines = 10;

int main( int argc, char* argv[] )
{
char szInput[_MAX_PATH], szOutput[_MAX_PATH];
char *pInName, *pOutName;
if( argc >= 2 ) // если в командной строке переданы параметры,
pInName = argv[1]; // то первый из них - имя обрабатываемого файла
else { // иначе - запрашиваем имя файла у пользователя
cout << "Введите имя исходного файла: ";
cin >> szInput;
pInName = szInput;
}
// открываем файл
ifstream fin( pInName, ios::in );
if( !fin.is_open() ) {
cout << "Ошибка при открытии файла "" << pInName << ""\n";
return 1;
}

if( argc >= 3 ) // если в командной строке переданы параметры,
pOutName = argv[2]; // то второй - имя результирующего файла
else { // иначе - запрашиваем имя файла у пользователя
cout << "Введите имя результирующего файла: ";
cin >> szOutput;
pOutName = szOutput;
}

// читаем файл построчно
cout << "\nЧтение файла '" << pInName << "'...";

char str[nLines][256]; // массив для 10 строк
int i = 0; // куда помещать очередную строку
unsigned nTotal = 0; // общее число строк
while( fin.rdstate() == ios::goodbit ) { // читаем очередную строку
fin.getline( str[i], sizeof str[0] );
++nTotal; // подсчитываем число строк
i = (i+1) % nLines; // индекс очередной строки
}
fin.close(); // закрываем файл

// создаем результирующий файл
ofstream fout( pOutName, ios::out );
if( !fout.is_open() ) {
cout << "Ошибка при создании файла "" << pOutName << ""\n";
return 2;
}

// записываем результат
cout << "\nЗапись файла '" << pOutName << "'...";

for( int j = 0; j < nLines && j < nTotal; ++j ) {
fout << str[i] << endl;
i = (i+1) % nLines; // индекс очередной строки
}
fout.close(); // закрываем файл
return 0;
}


Приведенное решение страдает недостатком - при чтении исходного файла не сохраняется признак конца строки, поэтому при выводе мы должны писать его "ручками":
fout << str[i] << endl;
В результате в выходной файл записывается одна лишняя строка.
Этого можно избежать, усложнив цикл чтения:
Код:

while( fin.rdstate() == ios::goodbit ) { // читаем очередную строку
//fin.getline( str[i], sizeof str[0] );
char s[256];
fin.getline( s, sizeof s );
if( !s[0] && fin.rdstate() != ios::goodbit )
break;

strcpy( str[i], s );

++nTotal; // подсчитываем число строк
i = (i+1) % nLines; // индекс очередной строки
}

Цена этого - лишнее копирование каждой прочитанной строки.
Этого недостатка лишен приведенный в приложении вариант с использованием файлового ввода/вывода в стиле C.

Программы проверены в MSVC++6.0, но должны компилироваться и в Borland C++ Builder 6.0.

Успехов!

Приложение:
// Написать консольное приложение, которое осуществляет копирование
// 10 последних строк из одного файла в другой.

#include <stdio.h>
#include <stdlib.h>

const int nLines = 10;

int main( int argc, char* argv[] )
{
char szInput[_MAX_PATH], szOutput[_MAX_PATH];
char *pInName, *pOutName;
if( argc >= 2 ) // если в командной строке переданы параметры,
pInName = argv[1]; // то первый из них - имя обрабатываемого файла
else { // иначе - запрашиваем имя файла у пользователя
printf( "Введите имя исходного файла: " );
pInName = gets( szInput );
}
// открываем файл
FILE* f = fopen( pInName,"rt" );
if( !f ) {
printf( "Ошибка при открытии файла "%s"\n", pInName );
return 1;
}

if( argc >= 3 ) // если в командной строке переданы параметры,
pOutName = argv[2]; // то второй - имя результирующего файла
else { // иначе - запрашиваем имя файла у пользователя
printf( "Введите имя результирующего файла: " );
pOutName = gets( szOutput );
}

// читаем файл построчно
printf( "\nЧтение файла '%s'...", pInName );

char str[nLines][256]; // массив для 10 строк
int i = 0; // куда помещать очередную строку
unsigned nTotal = 0; // общее число строк
while( fgets( str[i], sizeof str[0], f )) { // читаем очередную строку
++nTotal; // подсчитываем число строк
i = (i+1) % nLines; // индекс очередной строки
}
fclose( f ); // закрываем файл

// создаем результирующий файл
f = fopen( pOutName,"wt" );
if( !f ) {
printf( "Ошибка при создании файла "%s"\n", pOutName );
return 2;
}

// записываем результат
printf( "\nЗапись файла '%s'...", pOutName );

for( int j = 0; j < nLines && j < nTotal; ++j ) {
fputs( str[i], f );
i = (i+1) % nLines; // индекс очередной строки
}
fclose( f ); // закрываем файл

return 0;
}
5
Огромное Вам спасибо, мне нужно это уже на четверг, а сам я реально не успел бы сделать, т.к. с файлами на С++ не работал, писал только несложные консольные программки уровня университетских лабораторных первого курса. Я так понял файлы передаем в командной строке как аргументы?
Неизвестный
01.06.2010, 21:39
общий
amnick:
Сори Не прочитал описание вначале ответа
Форма ответа