Модуль 5. Переименование файла



# include < cstdlib >

#include <iostream>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include "rf.h"

#include "errl.h"

using namespace std;

#define BS 1

char buf1[BS];

void renamefile(char *path, char *nname)

{

int i=0, ffd, sfd;

ssize_t count;

ffd=open(path, O_RDONLY);

if(ffd==-1)

err1();

sfd=open(nname, O_WRONLY|O_CREAT|O_EXCL, 0644);

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

if ( sfd ==-1)

err1();

while(count=read(ffd,buf1,BS)>0)

Из первого файла (т.е. по файловому дескриптору ffd)считывается в буфер (который представляет собой массив) buf 1 число байт, равное BS.

{

write(sfd, buf1, count);

i++;

}

if(count==-1)

err1();

cout<<"Copy sucсesfull\n";

cout<<"Bytes copyed:"<<i;

close(ffd);

unlink(path);

cout<<"\nSource file sucsefully deleted\n";

close ( sfd );

}

Данная процедура работает по следующему алгоритму

1. Открытие файла для чтения

2. Создание нового файла

3. Копирование информации из первого файла (исходного) во второй(новый)

4. Удаление первого файла

Пункты 1,2,3 уже были рассмотрены, как отдельные модули. Рассмотрим теперь пункт 4

while ( count = read ( ffd , buf 1, BS )>0)

{

write(sfd, buf1, count);

i++;

}

Для понимания работы данного участка кода необходимо знать функции read и write.

read () пытается записать count байтов файлового описателя fd в буфер, адрес которого начинается с buf.

Если количество count равно нулю, то read () возвращает это нулевое значение и завершает свою работу. Если count больше, чем SSIZE _ MAX, то результат не может быть определен. Иными словами, чтение из первого файла и запись во второй продолжается до тех пор, пока переменная count не станет равной 0.

При успешном завершении вызова возвращается количество байтов, которые были считаны (нулевое значение означает конец файла), а позиция файла увеличивается на это значение. Если количество прочитанных байтов меньше, чем количество запрошенных, то это не считается ошибкой:

например, данные могли быть почти в конце файла, в канале, на терминале, или read () был прерван сигналом. В случае ошибки возвращаемое значение равно -1, а переменной е rrno присваивается номер ошибки. В этом случае позиция файла не определена.

write записывает до count байтов из буфера buf1 в файл, на который ссылается файловый описатель fd. POSIX указывает на то, что вызов write (), произошедший после вызова read () возвращает уже новое значение. Заметьте, что не все файловые системы соответствуют стандарту POSIX.

В случае успешного завершения возвращается количество байтов, которые были записаны (ноль означает, что не было записано ни одного байта). В случае ошибки возвращается -1, а переменной errno присваивается соответствующее значение. Если count равен нулю, а файловый описатель ссылается на обычный файл, то будет возвращен ноль и больше не будет произведено никаких действий. Для специальных файлов результаты не могут быть перенесены на другую платформу.

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

Далее, по алгоритму, следует удаление исходного файла, что в итоге даст нам, по сути, тот же файл, но с другим именем.

 

 

Модуль 6. Копирование файла

 

Процедура копирования файла ничем принципиально не отличается от -процедуры переименования файла. Единственное отличие- в процедуре копирования файла не происходит удаление исходного файла.

#include <cstdlib>

#include <iostream>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include "errl.h"

#include "cp.h"

using namespace std;

#define BS 1

char buf[BS];

void copyfile(char *path, char *nname)

{

int i=0, ffd, sfd;

ssize__t count;

ffd=open(path,O_RDONLY);

if(ffd==-1)

err1();

sfd=open(nname,O_WRONLY|O_CREAT|O_EXCL,0644);

if(sfd==-1)

err1();

while(count=read(ffd,buf,BS)>0)

{     

write(sfd,buf,count);

i++;

}

if(count==-1) err1();

cout<<"Copy succefull\n";

cout<<" Bytes copyed:\n"<<i;

close ( ffd );

close ( sfd );

}

Как видно, эта программа весьма незначительно отличается от предыдущей программы.

 

 

Модуль 7. Создание каталога

# include < cstdlib >

#include <iostream>

#include <sys/types.h>

#include <sys/stat.h>

#include "err1.h"

using namespace std;

void makedir(char *path)

{

if(mkdir(path,0777)==0)

cout<<" Directory created\n";

else err 1();

}

В данном модуле нет ничего сложного, создание каталога происходит с помощью функции mkdir

int mkdir (const char *pathname, mode_t mode);

mkdir пытается создать каталог, который называется pathname.

mode задает права доступа, которые получит свежесозданный каталог. Эти права стандартным образом модифицируются с помощью umask; права доступа оказываются равны (mode & ~ umask).

Свежесозданный каталог принадлежит фактическому владельцу процесса. Если на родительском каталоге установлен флаг setgid, или файловая система смонтирована с семантикой групп в стиле BSD, то новый каталог унаследует группу-владельца от своего родительского каталога; в противном случае группой-владельцем станет фактическая группа процесса.

Если у родительского каталога установлен бит setgid, то он будет установлен также и у свежесозданного каталога.

Конечно, ещё стоит прояснить момент с правами доступа, в нашем случае у каталога будут права 0777. Подробнее про маску доступа можно прочитать в Приложении 1, 3.

 

 

Модуль 8. Удаление каталога

 

Удаление каталога может показаться простой задачей. Но, в случае, если необходимо удалить вложенные каталоги и файлы, эта задача слегка усложняется. Рассмотрим модуль.

#include <cstdlib>

#include <unistd.h>

#include <iostream>

#include <sys/types.h>

#include <dirent.h>

#include <errno.h>

#include <string.h>

#include "errl.h"

#inctude "rd.h"

using namespace std;

void deldir(char *path)

{

DIR *dir;

int u;

struct dirent *sdir;

dir=opendir(path);

if(dir==NULL) err1();

chdir(path);

while((sdir=readdir(dir))!=NULL)

{

//cout << sdir->d_name<<"\n";

u=unlink(sdir->d_name);

if(u==-1 && errno==EISDIR)

{

if(strcmp(".", sdir->d_name)==0 || strcmp("..", sdir->d_name)==0)

continue;

deldir(sdir->d_ name);

}

if(u==-1 && errno==!EISDIR)

err1();

}

closedir(dir);

chdir("..");

if ( rmdir ( path )==-1) err 1();

}

Данную процедуру нелегко понять, просто взглянув на неё, так что рассмотрим все строки с неизвестными операторами.

DIR *dir; int u;

struct dirent *sdir;

dir=opendir(path);

if(dir==NULL) err1();

chdir ( path );

На данном участке кода происходит некоторого рода инициализация каталога. Он открывается, проверяется успешность попытки его открытия, текущий каталог меняется на данный.

while((sdir=readdir(dir))!=NULL)

{

u=unlink(sdir->d_name);

if(u==-1 && errno==EISDIR)

{

if(strcmp(".",sdir->d__name)==0 || strcmp("..", sdir->d_name)==0)

continue;

deldir(sdir->d_ name);

}

if(u==-l && errno==!EISDIR)

err 1();

}

Этот же участок без сомнения можно назвать самым важным в данном модуле. Здесь происходит рекурсивное удаление каталога. Рассмотрим его работу по подробнее.

while((sdir=readdir(dir))!=NULL)

Наш основной цикл. Те операторы, которые находятся в нём, будут выполняться, пока не будет достигнут конец каталога.

u=unlink(sdir->d_name);

Попытка удаления (к слову говоря, употреблять здесь слово «удаление» в его общем смысле не совсем верно, функция unlink удаляет ссылки на файл, а уже потом освобождается дисковое пространство) файла. По результатам этой попытки наш модуль будет вести так или иначе.

if(u==-1 && errno==EISDIR)

{

if(strcmp(".", sdir->d_name)==0 || strcmp("..", sdir->d_name)==0)

continue;

deldir(sdir->d_name);

}

if(u==-1 && errno==!EISDIR)

err 1();

Если наша попытка не удалась (то есть функция unlink вернула значение -1) и при этом последняя ошибка «EISDIR» (то есть ошибка «Это каталог»), то проверяем не является ли имя «.» или «..» (про эти имена можно более подробно прочитать в справочной литературе, скажу лишь что они обозначают родительский и текущий каталоги).Если имена совпали, то мы переходим на следующий итерационный шаг. Иначе просто заново входим в наш модуль (здесь и появляется рекурсия) передавая имя текущего каталога.

Если же попытка удаления не успешна и при этом ошибка не «EISDIR» то выводим ошибку.

closedir(dir);

chdir("..");

if(rmdir(path)==-1)

err 1();

}

Здесь же происходит соответственно закрытие каталога, переход в родительский каталог, удаление каталога (удаление в самом простом смысле, когда он пустой).

Таким образом, рекурсивный вызов заключается в том, что функция deldirвызывает саму себя до тех пор, пока программа не откроет такой каталог, который не содержит иных каталогов. При этом программа осуществляет удаление всех файлов в этом каталоге, выходит из этого (теперь пустого) каталога и удаляет его. И, так далее, до тех пор, пока не выйдет из исходного каталога и не удалит его.


Дата добавления: 2019-03-09; просмотров: 306; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!