Програми копіювання файлів - Лабораторная работа

бесплатно 0
4.5 50
Дослідження основних завдань та алгоритму роботи програм копіювання файлів: "COPY1.С" (функції роботи з file handles) та "COPY2.С" (функції потокового вводу-виводу). Повний розбір роботи обох кодів програм, їх тестування, модифікація та оптимізація.


Аннотация к работе
Навчитися користуватись програмами copy1.exe та copy2.exe.

План
Зміст

Список литературы
1. Навчитися користуватись програмами copy1.exe та copy2.exe

Програми «COPY1.С» та «COPY2.С» призначені для копіювання файлів. Програма «COPY1.С» використовує функції роботи з file handles, а «COPY2.С» - функції потокового вводу-виводу.

Для користування програмами: · їх необхідно скомпілювати та отримати виконавчі файли «COPY1.EXE» та «COPY2.EXE»;

· запустити необхідну програму за допомогою командного рядка, ввівши відповідно "імя_прогрми" "файл_з_якого_копіювати" "файл_в_який_копіювати";

програма копіювання файл

2. Розібрати роботу програм

2.1 Робота програми «COPY1.EXE»

Підключаємо заголовочні файли для використання функцій та змінних: #include //open(), eof(), read(), write(), close()

#include //getch()

#include //printf()

#include //exit()

#include //O_BINARY, O_RDONLY, O_WRONLY, O_CREAT, O_EXCL, O_TRUNC

#include //

#include //S_IREAD, S_IWRITE

#include //

#include //EEXIST

Макрос, що визначає розміру масиву

#define BUFSIZE 10000

Функція main() має два аргументи: цілочисельний аргумент argc який містить кількість аргументів у командному рядку та покажчик на масив покажчиків на рядки, де кожен вказує на певний аргумент командного рядка. void main( int argc, char **argv ) {

Оголошуємо змінні: int source, target;

int i;

char *buffer;

int count;

Перевіряємо чи правильна кількість аргументів у командному рядку. Якщо аргументів не три (програма, файл для копіювання, файл-копія), виводиться повідомлення про правильність заповнення командного рядка і виконання програми завершується. if( argc != 3 ){ printf( "

"

"Usage: COPY1 [d:][\\path]source_file [d:][\\path]target_file

" );

getch();

exit( 1 );

}

Відкриваємо файл, який будемо копіювати за допомогою функції open(). Для цього передаємо в якості параметрів покажчик на імя файлу (argv[ 1 ]) та вказуємо типи доступу до файлу. O_BINARY - прапор доступу у бінарному режимі. O_RDONLY - прапор доступу до файлу "лише для читання". Функція open() у випадку успішного виконання повертає file handle і встановлює курсор на початок файлу, а у випадку помилки повертає -1 та встановлює errno в один із наступних станів: ENOENT, EMFILE, EACCES, EINVACC.

Даним if-ом перевіряємо успішність відкриття файлу, який варто копіювати. if( ( source = open( argv[ 1 ], O_BINARY | O_RDONLY ) ) == -1 ) { printf( "\NOPEN source file error: %d", errno );

getch();

exit( 2 );

}

Відкриваємо файл, в який будемо копіювати за допомогою тієї ж функції open().

Прапор доступу до файлу встановлюємо в один із положень: · O_BINARY - бінарний;

· O_WRONLY - для запису;

· O_CREAT - створюється;

· O_EXCL - перезаписується.

Прапор способу відкриття встановлюємо в один із положень: · S_IREAD - може бути прочитаний;

· S_IWRITE - може бути записаний. target = open( argv[ 2 ], O_BINARY | O_WRONLY | O_CREAT | O_EXCL, S_IREAD | S_IWRITE );

Якщо при відкритті(створенні) файлу до якого буде відбуватися копіювання, errno дорівнює EEXIST (тобто файл з таким імям вже існує), повідомити про існування файлу та запитати про необхідність його перезапису. if( errno == EEXIST ) { printf( "\NFILE already exists. Overwrite? (Y/N)

" );

i = getch();

if( ( i == "y" ) || ( i == "Y" ) ) target = open( argv[ 2 ], O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE );

}

Перевірити чи вдалося створити файл . if( target == -1 ) { printf( "\NOPEN target file error: %d", errno );

getch();

exit( 2 );

}

Цілочисельній змінній count присвоїти значення макросу BUFSIZE. count = BUFSIZE;

Виділити память на масив buffer розміром count, та перевірити чи память дійсно виділена. if( ( buffer = ( char* )malloc( count ) ) == NULL ) { printf( "\NNOT enough memory" );

getch();

exit( 3 );

}

За допомогою оператора while, який буде виконуватися доти, доки функція eof() не знайде закінчення файлу, який копіюється, будемо виконувати читання та запис з вихідного файлу у вхідний. while( !eof( source ) ) {

За допомогою функції read() зчитаємо із файлу source до масиву buffer count байтів. if( ( count = read( source, buffer, count ) ) == -1 ) { printf( "\NREAD file error: %d", errno );

getch();

exit( 4 );

}

За допомогою функції write() запишемо до файлу target із масиву buffer count байтів. if( ( count = write( target, buffer, count ) ) == -1 ) { printf( "\NWRITE file error: %d", errno );

getch();

exit( 5 );

}

}

Закриємо відкриті файли та звільнимо память із буферу. close( source );

close( target );

free( buffer );

Проінформуємо про успішне копіювання. printf("File copy...");

getch();

}

2.2 Робота програми «COPY1.EXE»

Підключаємо заголовочні файли для використання функцій та змінних: #include

#include

#include

Оголошуємо прототип функції void filecpy( FILE *stream_from, FILE *stream_to );

Оголошуємо два символьних масиви розміром BUFSIZ*10;

char buf1[ BUFSIZ * 10 ];

char buf2[ BUFSIZ * 10 ];

Функція main() має два аргументи: цілочисельний аргумент argc який містить кількість аргументів у командному рядку та покажчик на масив покажчиків на рядки, де кожен вказує на певний аргумент командного рядка. void main( int argc, char *argv[] ) {

Оголосимо змінні: time_t start, end;

FILE *stream_from, *stream_to;

Перевіряємо чи правильна кількість аргументів у командному рядку. Якщо аргументів не три (програма, файл для копіювання, файл-копія), виводиться повідомлення про правильність заповнення командного рядка і виконання програми завершується. if( argc < 3 ) { printf( "\NUSAGE:"

" COPY2 [d:][\\path]source_file [d:][\\path]target_file

" );

exit( 1 );

}

Відкриваємо файл, який варто копіювати, для читання. if( ( stream_from = fopen( argv[ 1 ], "rt" ) ) == NULL ) { printf( "\NOPEN source file error: %d", errno );

exit( 1 );

}

Відкриваємо файл, в який варто копіювати, для запису(якщо файлу не існує, він створюється, якщо існує - перезаписується). stream_to = fopen( argv[ 2 ], "wt " );

Вмикаємо тактовий лічильник, і його стартове значення присвоюємо змінній start. start = clock();

Викликаємо функцію для копіювання і передаємо їй покажчик на файл який варто копіювати і на файл до якого необхідно копіювати. filecpy( stream_from, stream_to );

Вимикаємо тактовий лічильник, і його фінальне значення присвоюємо змінній end. end = clock();

Друкуємо інформацію про затрачений час на виконання функції і про розмір буферу який довелося використати. printf( "Copying time is %5.1f. Buffer size is %d bytes

", ( ( float )end - start ) / CLK_TCK, BUFSIZ );

Відкриваємо файл, який варто копіювати, та файл до якого варто копіювати. if( ( stream_from = fopen( argv[ 1 ], "rt") ) == NULL ) exit( 1 );

stream_to = fopen( argv[ 2 ], "wt " );

Задаємо буфери за допомогою функції setvbuf(), які будуть використовуватися у якості буферів потоків для операцій вводу/виводу. Причому для буферизації будемо використовувати повний обєм буфера, оскільки використовується режим _IOFBF. setvbuf( stream_from, buf1, _IOFBF, sizeof( buf1 ) );

setvbuf( stream_to, buf2, _IOFBF, sizeof( buf2 ) );

Викликаємо функцію для копіювання, при цьому підраховуємо затрачений на її виклик час та використану память. start = clock();

filecpy( stream_from, stream_to );

end = clock();

printf( "Copying time is %5.1f. Buffer size is %d bytes

", ( ( float )end - start ) / CLK_TCK, BUFSIZ * 10 );

Відкриваємо файл, який варто копіювати, та файл до якого варто копіювати. if( ( stream_from = fopen( argv[ 1 ], "rt") ) == NULL ) exit( 1 );

stream_to = fopen( argv[ 2 ], "wt " );

Задаємо буфери. Але потіки не буферизується, оскільки використовується режим _IONBF. setvbuf( stream_from, NULL, _IONBF, 0 );

setvbuf( stream_to, NULL, _IONBF, 0 );

Викликаємо функцію для копіювання, при цьому підраховуємо затрачений на її виклик час та використану память. start = clock();

filecpy( stream_from, stream_to );

end = clock();

printf( "Copying time is %5.1f. Buffers is not used

", ( ( float )end - start ) / CLK_TCK );

exit( 0 );

}

Функція копіювання файлів з використанням потоку вводу/виводу.

Аргументи: FILE *stream_from - покажчик на потік звідки копіювати;

FILE *stream_to - покажчик на потік в який копіювати;

Функція нічого не повертає і не використовує глобальних змінних. void filecpy( FILE *stream_from, FILE *stream_to ) {

Оголошуємо символьний масив на 256 знаків char linebuf[ 256 ];

За допомогою оператора while та функції feof() шукаємо кінець потоку з якого копіюємо. while( !feof( stream_from ) ) {

Використовуючи функцію fgets(), до масиву linebuf заносимо значенням із вихідного потоку stream_from. if( fgets( linebuf, 255, stream_from ) == NULL ) break;

Використовуючи функцію fputs(), із масив linebuf виштовхуємо значенням до вхідного потоку stream_to. if( fputs( linebuf, stream_to ) == EOF ) break;

}

Закриваємо файли. fclose( stream_from );

fclose( stream_to );

}

3. Експерименти з «copy1.c»

В програмі copy1.c замінити бінарний режим доступу до обох файлів на текстовий і запустити програму для копіювання досить великого бінарного файлу. Результати експерименту зафіксувати в зошиті. Пояснити причину ефекту

При зміні з бінарного режиму доступу до обох файлів на текстовий відбувається не повне копіювання (створений файл менший), а лише до символу Ctrl-Z (ASCII 1Ah), адже вважається, що досягнуто кінець файлу (умова EOF).

В програмі copy1.c замінити бінарний режим доступу до файлу, який записується, на текстовий і запустити програму. Результати експерименту зафіксувати в зошиті. Пояснити причину ефекту.

При зміні з бінарного режиму доступу до файлу, який записується, на текстовий створюється не достовірна копія (створений файл більший), оскільки відбувається відображення кожного символу який був зчитаний у бінарному режимі. Таким чином пара, наприклад, символів CR LF не перетворюється в один символ нового рядка “

”, а виводиться окремо як два символи.

4. Експерименти з «copy2.c»

В програмі copy2.c знайти оптимальний розмір буферу. Обґрунтувати вибір.

На мою думку, оптимальним розміром буферу буде розмір кратний числу 512. Це можна поясноит тим, що функція дає виграш в продуктивності при перенесенні відразу цілої групи байтів (блоку) за одне звернення до функції. Максимальний виграш досягається тоді, коли розмір блоку який переноситься з програми в файл кратний розміру сектора диску, а саме 512 байт.

В програмі copy2.c модифікувати програму так, щоб вона виводила на екран вміст файлу за допомогою функцій puts(), fputs(), printf(), fwrite(). Результати експерименту зафіксувати в зошиті. Пояснити причину ефекту.

При використанні функцій виведення на екран, відбувається виведення не екран інформації з вихідного файлу у тому вигляді, який передбачений відповідною функцією. При цьому затрачається більше часу на виконання програми.

Контрольні запитання

1. Чим відрізняється текстовий режим доступу до файлу від бінарного?

Як для потокових так і для префіксних функцій файлового введення-виведення можливі два різних режими доступу до файлу: текстовий та бінарний. В текстовому режимі виконується трансляція символів CR LF (0Dh 0Ah). При читанні інформації з файлу в цьому режимі пара символів CR LF перетворюється в один символ нового рядка “

” а при записі - символ нового рядка перетворюється в пару символів CR LF. Крім того, як тільки з файлу зчитується символ Ctrl-Z (ASCII 1Ah), вважається, що досягнуто кінець файлу (умова EOF). Таким чином, в текстовому режимі не вдається прочитати інформацію, розташовану після символу Ctrl-Z. При виконанні файлового введення-виведення в бінарному режимі жодного перетворення символів не відбувається, а всі вони розглядаються як такі що не мають якогось особливого сенсу. Режим доступу до файлу задається під час відкриття файлу через бібліотечну функцію відкриття або спеціальною зовнішньою змінною _fmode.

2. Що таке дескриптор(handle) файлу?

Відкриття файлів виконує функція АН = 3Dh MS-DOS. Пара регістрів DS:DX вказує на ASCIIZ-рядок, що містить специфікацію файлу, що відкривається як регулярний, або імя драйверу символьного пристрою. В регістрі AL задається режим відкриття файлу. Значення яке повертається функцією в регістр АХ є ціле число, це префікс (handle) або дескриптор файлу. При всіх наступних операціях доступу до відкритого файлу в MS-DOS для ідентифікації файлу повідомляється тільки префікс.

2. Чим відрізняється префіксний доступ до файлу від потокового?

Бібліотечні функції Turbo C для роботи з файлами можна поділити на дві групи: потокові та префіксні. Як потокові, так і префіксні функції звертаються, в принципі, до тих самих викликам функцій MS-DOS. Однак, потокові функції виконують додаткову буферизацію інформації. Це призводить до подвійної буферизації інформації: на рівні бібліотечної функції і на рівні MS-DOS. Префіксні функції не виконують додаткову буферизацію, а відразу звертаються до префіксних функцій MS-DOS.

3. В яких випадках більше доцільний потоковий доступ? Чому?

Префіксні функції дають виграш в продуктивності при перенесенні відразу цілої групи байтів (блоку) за одне звернення до функції. Максимальний виграш досягається тоді, коли розмір блоку який переноситься з програми в файл кратний розміру сектора диску (512 байт). Перенесення інформації між файлом і Сі-програмою по символам або по рядкам виявляється більш ефективним при використанні функцій потокового файлового введення-виведення.

Висновок

Отже, при виконанні даної лабораторної роботи було використано дві програми копіювання файлів «COPY1.С» та «COPY2.С». Програма «COPY1.С» використовує функції роботи з file handles, а «COPY2.С» - функції потокового вводу-виводу. Було проведено повний розбір роботи обох кодів програм, їх тестування, модифікацію та оптимізацію.

Загалом у ході виконання лабораторної роботи були отримані всі необхідні знання та практичні навички для роботи з файлами.

Список використаної літератури

1. Касаткін А.І. Управление ресурсами. - Минск: Вышейшая школа, 1992.

2. Касаткін А.І. Системное программирование. - Минск: Вышейшая школа, 1991.

3. Власенко О.В., Данильченко О.М., Северин О.О. Системне прогрмамування. Курс лекцій. Частина 1. (бібліотека ЖІТІ)

Размещено на
Заказать написание новой работы



Дисциплины научных работ



Хотите, перезвоним вам?