Сообщений 0    Оценка 16        Оценить  
Система Orphus

Как программно скопировать/переместить/переименовать/удалить файл?

Автор: Игорь Вартанов

Версия текста: 1.0.1

Рассмотрение начнем с системных функций Windows. Сразу необходимо напомнить, что имея дело с файлами, всегда необходимо помнить об ограничении длины полного имени файла, накладываемого операционной системой. Для ANSI-версий функций (единственно доступных для ОС Windows 95/98), выполняющих файловые операции, максимальная длина буфера, содержащего полный путь к файлу (включая ноль-терминатор) равна MAX_PATH (что составляет 260 для PC-архитектуры и 256 для MAC). Для Windows NT/2000 доступны UNICODE-версии функций, которые способны "расширить этот предел вплоть до 32 000 широких символов" (цитировалось дословно по MSDN; точное число символов, скрывающееся за формулировкой "вплоть до 32 000" мне не известно). В последнем случае UNICODE-строка, содержащая полный путь к файлу, должна начинаться символами "\\?\". Для более полной информации см. раздел "File Name Conventions" в MSDN.

Копирование файла выполняет функция CopyFile( ), при этом она позволяет настраивать поведение в зависимости от того, существует или нет целевой файл toName.

BOOL WINAPI CopyFile(LPCTSTR fromName, LPCTSTR toName, BOOL failIfExists);

Если failIfExists установлен в TRUE, то при условии, что файл с именем toName уже существует, то функция завершится ошибкой. В противном случае (failIfExists = FALSE) имеющийся файл toName будет перезаписан.

Перемещение и переименование файла с точки зрения файловой системы не имеет отличий, поскольку и в первом, и во втором случае изменяется полное имя файла. Эту операцию можно выполнить функцией MoveFile( ).

BOOL WINAPI MoveFile(LPCTSTR fromName, LPCTSTR toName);

Функция MoveFile имеет ряд ограничений. Во-первых, она не позволяет обработать ситуацию, когда уже имеется файл с именем toName. Второе ограничение связано с тем, что функция MoveFile( ) способна перемещать не только файлы, но и каталоги. Так вот перемещение каталога должно происходить в пределах одного тома.

Для преодоления указанных ограничений имеется функция MoveFileEx( ).

BOOL WINAPI MoveFileEx(LPCTSTR fromName, LPCTSTR toName, DWORD dwFlags);

Чтобы при перемещении файла можно было перезаписать имеющийся уже файл с именем toName, необходимо установить флаг MOVEFILE_REPLACE_EXISTING. Для перемещения каталога на другой том необходимо установить флаг MOVEFILE_COPY_ALLOWED.

Удаление файла может быть выполнено функцией DeleteFile( ).

BOOL WINAPI DeleteFile(LPCTSTR fileName);
ПРЕДУПРЕЖДЕНИЕ
Указанная функция при работе под Windows95 способна удалить и открытый файл, и файл, отображенный в память. Авторы MSDN рекомендуют закрыть файл перед тем как попытаться удалить его.

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

// #include <windows.h>
// #pragma comment(lib,"shell32")

int SHFileOperation(LPSHFILEOPSTRUCT lpFileOp);

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

typedef struct _SHFILEOPSTRUCT{ 
    HWND         hwnd;                   // хэндл окна-владельца диалога
    UINT         wFunc;                  // тип файловой операции
    LPCTSTR      pFrom;                  // путь-источник
    LPCTSTR      pTo;                    // путь-назначение
    FILEOP_FLAGS fFlags;                 // флаги операции
    BOOL         fAnyOperationsAborted;  // признак прерванной операции 
    LPVOID       hNameMappings; 
    LPCSTR       lpszProgressTitle;      // заголовок диалога
} SHFILEOPSTRUCT, *LPSHFILEOPSTRUCT;

Тип файловой операции задается полем wFunc и может принимать значения FO_COPY, FO_DELETE, FO_MOVE и FO_RENAME. Поле fFlags может содержать большое количество разнообразных флагов, изменяющихся в зависимости от типа выполняемой операции и необходимого поведения функции. Так флаг FOF_SILENT позволяет подавить вывод диалога, отображающего выполнение файловой операции во времени (прогресс-диалога), флаг FOF_NOCONFIRMATION подавляет вывод запросов на подтверждение выполнения файловой операции, флаг FOF_NOCONFIRMMKDIR подавляет вывод запросов на подтверждение создания каталогов во время выполнения копирования и перемещения каталогов, флаг FOF_NOERRORUI подавляет вывод сообщений об ошибках, возникших во время выполнения операции, флаг FOF_NORECURSION позволяет выполнить операцию только с содержимым указанного каталога, флаг FOF_SIMPLEPROGRESS позволяет отображение прогресс-диалога без вывода имен файлов и каталогов, с которыми производится операция (пример применения функции SHFileOperation( ) см. в статье "Как программно удалить каталог со всеми файлами и подкаталогами?").

Кроме того, функция SHFileOperation( ) позволяет выполнить удаление файла в "Корзину". Для этого необходимо к набору флагов добавить флаг FOF_ALLOWUNDO и обязательно указать полный путь к файлу в поле pFrom.

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

Копирование файла средствами рантайм-библиотеки возможно лишь при помощи открытия файла-источника и файла-приемника и непосредственным копированием содержимого из одного в другой.

#include <stdio.h>
#include <fcntl.h>
#include <io.h>

#define BUF_SIZE 1024

int  src, dst, size;
char buf[BUF_SIZE];

src = _open(sourceFile, _O_BINARY | _O_RDONLY);
dst = _open(destFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY);
while(!_eof(src))
{
    if( ( size = _read( src, buf, BUF_SIZE ) ) == -1 )
    {
        perror("Read error\n");
        break;
    }
    if( _write( dst, buf, size ) == -1 )
    {
        perror("Write error\n");
        break;
    }
}
_close(dst);
_close(src);

Удаление файла средствами рантайм-библиотеки возможно при помощи функции remove( ) (или _unlink( )).

#include <stdio.h>

int err = remove(szFileToDelete);

Перемещение/переименование файла в рантайм-библиотеке выполняет функция rename( ):

#include <stdio.h>
#include <io.h>

int err = 0;
if(!_access( szToName, 0 ))
    err = _unlink( szToName );
if(!err)
    err = rename( szFromName, szToName );

Функция rename( ) имеет ограничения - файл szToName не должен существовать. Поэтому сначала необходимо выяснить, существует такой файл или нет, и, в случае, если существует, предварительно удалить его.

В заключение необходимо заметить, что данная статья выполняет лишь роль обзорно-ознакомительной, и ни в коей мере не может считаться полноценным руководством по файловым операциям в среде Windows.


Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав.
    Сообщений 0    Оценка 16        Оценить