Смекни!
smekni.com

Програми копіювання файлів (стр. 1 из 2)

Міністерство освіти і науки України

Житомирський державний технологічний університет

Лабораторна робота №1

з курсу «Системне програмування»

на тему: «Програми копіювання файлів»

м.

Житомир 2011 р.

Зміст

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

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

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

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

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

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

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

Висновок

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

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

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

Для користування програмами:

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

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

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


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

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

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

#include <io.h> //open(), eof(), read(), write(), close()

#include <conio.h> //getch()

#include <stdio.h> //printf()

#include <stdlib.h> //exit()

#include <fcntl.h> //O_BINARY, O_RDONLY, O_WRONLY, O_CREAT, O_EXCL, O_TRUNC

#include <sys&bsol;types.h> //

#include <sys&bsol;stat.h> //S_IREAD, S_IWRITE

#include <alloc.h> //

#include <errno.h> //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( "&bsol;n"

"Usage: COPY1 [d:][&bsol;path]source_file [d:][&bsol;path]target_file&bsol;n" );

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( "&bsol;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( "&bsol;nFile already exists. Overwrite? (Y/N)&bsol;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( "&bsol;nOpen target file error: %d", errno );

getch();

exit( 2 );

}

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

count = BUFSIZE;

Виділити пам’ять на масив buffer розміром count, та перевірити чи пам’ять дійсно виділена.

if( ( buffer = ( char* )malloc( count ) ) == NULL ) {

printf( "&bsol;nNot enough memory" );

getch();

exit( 3 );

}

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

while( !eof( source ) ) {

За допомогою функції read() зчитаємо із файлу source до масиву buffer count байтів.

if( ( count = read( source, buffer, count ) ) == -1 ) {

printf( "&bsol;nRead file error: %d", errno );

getch();

exit( 4 );

}

За допомогою функції write() запишемо до файлу target із масиву buffer count байтів.

if( ( count = write( target, buffer, count ) ) == -1 ) {

printf( "&bsol;nWrite file error: %d", errno );

getch();

exit( 5 );

}

}

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

close( source );

close( target );

free( buffer );

Проінформуємо про успішне копіювання.

printf("File copy...");

getch();

}

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

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

#include <stdio.h>

#include <stdlib.h>

#include <time.h>

Оголошуємо прототип функції

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( "&bsol;nUsage:"

" COPY2 [d:][&bsol;path]source_file [d:][&bsol;path]target_file&bsol;n" );

exit( 1 );

}

Відкриваємо файл, який варто копіювати, для читання.

if( ( stream_from = fopen( argv[ 1 ], "rt" ) ) == NULL ) {

printf( "&bsol;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&bsol;n",

( ( 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&bsol;n",

( ( 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&bsol;n",

( ( 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 не перетворюється в один символ нового рядка “&bsol;n”, а виводиться окремо як два символи.