Копирование файлов с использованием библиотеки С
Программа Срс
Обращение к программе производится из командной строки: Срс
файл 1, файл2 - копирование файлов с использованием библиотеки С, копирует файл1 в файл2 .
#include <stdio.h>
#include <errno.h>
#define BUF_SIZE 256
int main (int argc, char *argv [])
{
FILE *in_file, *out_file; char rec
[BUF_SIZE]; size_t bytes_in,
bytes_out;
if (argc != 3)
{
printf (“Использование: Cрc file1 File2\n”);
return 1;
}
in_file = fopen (argv [1], “rb”);
if (in_file == NULL)
{
perror (argv [1] ) ;
return 2;
}
out_file = fopen (argv [2], “wb”);
if (out_file == NULL)
{
perror (argv [2] ) ;
return 3;
}
/* Обрабатываем входной файл по одной записи. */
while ( (bytes_in = fread (rec, 1, BUF_SIZE, in_file) ) > 0)
{
bytes_out = fwrite (rec, 1, bytes__in, out_file) ;
if (bytes_out != bytes_in)
{
perror («Неисправимая ошибка записи.»);
return 4;
}
}
fclose (in_file);
fclose (out_file);
}
Программа запускается из командной строки.
Копирование файлов с использованием API Win32
Программа Сpw
Обращение к программе производится из командной строки: Cpw
файл 1, файл 2 – копирование файлов с использованием API Win32, копирует файл1 в файл2.
#include <windows.h>
#include <stdio.h>
#define BUF_SIZE 256
int main (int argc, LPTSTR argv [])
{
HANDLE hIn, hOut;
DWORD nIn, nOut;
CHAR Buffer [BUF_ SIZE];
if (argc != 3)
{
printf (“Использование: CpW file1 File2\n”);
return 1;
}
hIn = CreateFile (argv [1], GENERIC_READ, 0, NULL,
OPEN_EXISTING, 0, NULL);
if (hIn = = INVALID_HANDLE_VALUE)
{
printf («Нельзя открыть входной файл. Ошибка: %х\n”,
GetLastError ());
return 2;
}
hOut = CreateFile (argv [2], GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
NULL);
if (hOut = =INVALID_HANDLE_VALUE)
{
printf («Нельзя открыть выходной файл. Ошибка: %х\n”,
GetLastError () ) ;
return 3;
}
while (ReadFile (hIn, Buffer, BUF_SIZE, &nIn, NULL) && nIn > 0)
{
WriteFile (hOut, Buffer, nIn, &nOut, NULL);
if (nIn != nOut)
{
printf (“Неисправимая ошибка записи: %x\n”, GetLastError
( ) ) ;
return 4;
}
}
CloseHandle (hIn);
CloseHandle (hOut);
return 0;
}
Данный пример иллюстрирует некоторые особенности программирования в Win32.
1. <windows.h> включается всегда и содержит все определения функций и типов данных Win32.
2. Все объекты Win32 идентифицируются переменными типа HANDLE, и к большинству объектов применяется одна универсальная функция - CloseHandle.
3. Рекомендуется закрывать все открытые дескрипторы, когда они больше не требуются, чтобы освободить ресурсы. Тем не менее, при завершении процесса дескрипторы закрываются автоматически.
4. В Win32 определены многочисленные символические константы и флаги. Их имена обычно очень длинны и часто описывают их назначение. Типичное имя - INVALID_HANDLE_VALUE или GENERIC_READ.
5.Функции типа ReadFile и WriteFile возвращают логические значения, а не количество байтов (которое передается в параметре). Это несколько изменяет логику цикла. Конец файла обнаруживается по нулевому количеству байтов и не приводит к неудаче операции.
6.Функция GetLastError позволяет в любой момент получить системные коды ошибок в форме DWORD.
Копирование файлов с использованием функции полуфабриката Win32
Win32 содержит множество функций-полуфабрикатов, которые объединяют несколько функций для выполнения часто встречающихся задач. В некоторых случаях эти функции-полуфабрикаты могут улучшить быстродействие. Например, CopyFile значительно упрощает программу. В частности, здесь совершенно не нужно искать оптимальный размер буфера, который в двух предыдущих программах был произвольно задан в 256 байт.
Реализация программы копирования файлов для Win32 с использованием CopyFile достаточно проста и обеспечивает высокое быстродействие.
Обращение производится из командной строки: сpCF файл1
файл2 - копирует файл1 в файл2.
#include <windows.h>
#include <stdio.h>
int main (int argc, LPTSTR argv [])
{
if (argc != 3)
{
printf (“Использование: cpCF file1 file2\n”);
return 1;
}
if (!СopyFile (argv [1], argv [2], FALSE))
{
printf (“Ошибка CopyFile: %x\n”, GetLastError ());
return 2;
}
return 0;
}
Приведенные программы копирования файлов демонстрируют многочисленные различия между библиотекой С и Win32. Примеры с использованием Win32 демонстрируют стиль программирования и соглашения Win32, но дают лишь первое представление о функциональных возможностях, доступных в Win32.
Содержание работы
1. Изучить программы копирования файлов.
2. Последовательно набрать и отладить программы копирования файлов в среде Visual Studio C++ .NET 2003.
3. Выполнить задание по копированию файла 1 в файл 2, выбрав произвольные имена файлов в различных программах.
4. Подготовить отчет по выполненной работе.
5. В отчете ответить на контрольные вопросы.
5. Порядок выполнения программ в среде Visual C++ .NET 2003
1. Запустить Microsoft Visual Studio C++ .NET 2003.
2. Создать проект под именем cpC. Для этого выполнить команды меню File, New, Project.
Рис.1. Создание нового проекта cpC консольного приложения
На появившейся вкладке New Project выбрать Win32 Console Project, в окне Name: набрать имя проекта cpC. В окне Location: набрать путь к папке, в которой будет записан проект и щелкнуть мышью OK. На появившейся вкладке щелкнуть мышью Finish.
3.На экране появляется текст файла cpC.cpp, в котором находится заготовка программы консольного приложения.
Рис 2. Содержимое файла cpC.cpp
4.После набора текста программы выполняется ее редактирование с использованием из меню Build команды Build Solution. В случае исправления всех ошибок в папке Debug проекта создается исполняемый файл с расширением .exe - cpC.exe, который необходимо выполнить.
5.Выполнение программы производится из командной строки. Для этого можно использовать программу Far, при этом следует указать имя исходного файла, который должен быть создан до запуска программы cpC.exe, и имя файла, куда производится копирование.
6.Аналогично выполняется создание проектов cpW, cpCF, создание исполняемых файлов cpW.exe, cpCF.exe и выполнение программ копирования файлов с использованием Win32 и фунции-полуфабриката Win32.
Содержание отчета
В отчет должны быть включены следующие разделы:
1.Общие сведения об интерфейсе прикладного программирования API Win32.
2.Особенности использования API Win32 для копирования файлов.
3.Листинги различных программ копирования файлов.
4.Результаты копирования файлов, выполненных с использованием стандартной библиотеки С, с использованием Win32 и с использованием функции-полуфабриката Win32.
7.Контрольные вопросы
1. Что такое API Win32?
2. Какие операционные системы обслуживает API Win 32?
3.Какие особенности имеет API Win 32?
4. Какие преимущества программирования дает API 32?
5. Какой основной тип переменных используется в Win 32?
6. Для управления каких систем могут быть написаны программы с использованием Win32?
7. Что означает строка int main (int argc, LPTSTR argv [])?
8. Поясните, какую функцию выполняет данный оператор: hIn = CreateFile (argv [1], GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
9. Поясните, какую функцию выполняет данный оператор: hOut = CreateFile (argv [2], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
10.Поясните, какую функцию выполняет данный оператор: while (ReadFile (hIn, Buffer, BUF_SIZE, &nIn, NULL) && nIn > 0)
11. Поясните, какую функцию выполняет данный оператор: WriteFile (hOut, Buffer, nIn, &nOut, NULL);
12. Поясните, какую функцию выполняет данный оператор: if (!СopyFile (argv [1], argv [2], FALSE)).
ЛИТЕРАТУРА
1. Побегайло А. Системное программирование в Windows. – СПб.: БХВ-Петербург, 2006
2. Лав Р. Linux. Системное программирование. – СПб.: Питер, 2008
3. Несвижский В. Программирование аппаратных средств в Windows. - СПб.: БХВ-Петербург, 2008
4. Джонсон М. Харт. Системное программирование в среде Win32. M.: Издательский дом «Вильямс», 2001
5. Джеффри Рихтер. Windows. Создание эффективных Win32-приложений с учетом специфики 64-разрядной версии Windows/ Пер. с англ. — 4-е изд. — СПб.: Питер; М.: Издательство «Русская Редакция»; 2008
6. Ал Вильямс. Системное программирование в Windows 2000. - СПб.: Питер, 2001
7. Румянцев И.В. Азбука программирования в Win32 API. – М.: Горячая линия – телеком, 2001
ЛАБОРАТОРНАЯ РАБОТА № 6
Тема работы: Запуск и завершение процесса. Создание и завершение потока. Синхронизация
Цель работы: Приобрести практические навыки работы с потоками в ОС Windows с использованием Win32 API
Ниже представлен листинг:
?
#include <windows.h> LRESULT CALLBACK WindowProcess(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCommandLine, int nCommandShow){ TCHAR className[] = L"Мой класс"; HWND hWindow; MSG message; WNDCLASSEX windowClass; windowClass.cbSize = sizeof(windowClass); windowClass.style = CS_HREDRAW | CS_VREDRAW; windowClass.lpfnWndProc = WindowProcess; windowClass.lpszMenuName = NULL; windowClass.lpszClassName = className; windowClass.cbWndExtra = NULL; windowClass.cbClsExtra = NULL; windowClass.hIcon = LoadIcon(NULL, IDI_WINLOGO); windowClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO); windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); windowClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); windowClass.hInstance = hInst; if(!RegisterClassEx(&windowClass)) { MessageBox(NULL, L"Не получилось зарегистрировать класс!", L"Ошибка", MB_OK); return NULL; } hWindow = CreateWindow(className, L"Программа ввода символов", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, NULL, CW_USEDEFAULT, NULL, (HWND)NULL, NULL, HINSTANCE(hInst), NULL ); if(!hWindow){ MessageBox(NULL, L"Не получилось создать окно!", L"Ошибка", MB_OK); return NULL; } ShowWindow(hWindow, nCommandShow); UpdateWindow(hWindow); while(GetMessage(&message, NULL, NULL, NULL)){ TranslateMessage(&message); DispatchMessage(&message); } return message.wParam; } LRESULT CALLBACK WindowProcess(HWND hWindow, UINT uMessage, WPARAM wParameter, LPARAM lParameter) { HDC hDeviceContext; PAINTSTRUCT paintStruct; RECT rectPlace; HFONT hFont; static char text[2]={' ','\0'}; switch (uMessage) { case WM_CREATE: MessageBox(NULL, L"Пожалуйста, вводите символы и они будут отображаться на экране!", L"ВНИМАНИЕ!!!", MB_ICONASTERISK|MB_OK); break; case WM_PAINT: hDeviceContext = BeginPaint(hWindow, &paintStruct); GetClientRect(hWindow, &rectPlace); SetTextColor(hDeviceContext, NULL); hFont=CreateFont(90,0,0,0,0,0,0,0, DEFAULT_CHARSET, 0,0,0,0, L"Arial Bold" ); SelectObject(hDeviceContext,hFont); DrawText(hDeviceContext, (LPCWSTR)text, 1, &rectPlace, DT_SINGLELINE|DT_CENTER|DT_VCENTER); EndPaint(hWindow, &paintStruct); break; case WM_KEYDOWN: switch (wParameter) { case VK_HOME:case VK_END:case VK_PRIOR: case VK_NEXT:case VK_LEFT:case VK_RIGHT: case VK_UP:case VK_DOWN:case VK_DELETE: case VK_SHIFT:case VK_SPACE:case VK_CONTROL: case VK_CAPITAL:case VK_MENU:case VK_TAB: case VK_BACK:case VK_RETURN: break; default: text[0]=(char)wParameter; InvalidateRect(hWindow, NULL, TRUE); break; }break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWindow, uMessage, wParameter, lParameter); } return NULL; } |
Данная программа выводит цифры и буквы, при этом не реагирует на нажатие дополнительных клавиш, типа enter, shift и т.д.
В функции WinMain() ничего нового. А в WindowProcess() мы добавили обработчики событий нажатия клавиши.
Нажатие любой клавиши автоматически посылает системе аппаратное сообщение, которое обрабатывается и высылается приложению. За эту операцию отвечает сообщение WM_KEYDOWN.
Его описание сложно и на данном этапе не имеет смысла, так как мы не включили кириллицу. При посылке этого сообщения в wParameter записывается значение нажатой клавиши. Конечно же, всё зависит от клавиатуры, раскладки. Поэтому всего кодов для клавиш много и мы не будем описывать, что делать при нажатии той или иной, а просто исключим значения не нужных нам клавиш.
С 87-й по 101-ю строки мы обрабатываем сообщение WM_KEYDOWN (нажатие клавиши). Сначала мы создаём переключатель switch для значения wParameter, куда записан идентификатор клавиши. С 90-й по 95-ю строки мы исключаем значения home, end, page up, page down, стрелка влево, стрелка вправо, стрелка вверх, стрелка вниз, delete, shift, space, ctrl, caps lock, alt, tab, backspace, enter соответственно. Возможно, на вашей клавиатуре есть ещё клавиши, вы можете также их исключить при необходимости, потому что при нажатии будет «абракадабра». То есть если в идентификаторе wParameter у нас эти значения, мы ничего не делаем – в 96-й строке оператор break.
А под значениями default у нас выполняется преобразование. В 66 строке мы создали статическую строку типа char из 2-х элементов. Статическая она, потому что в процессе работы программы мы неоднократно выходим из WindowProcess() в цикл обработки с GetMessage(), расположенный в WinMain(), а значение клавиши нам нужно сохранять. Ну а в 98 строке мы инициализируем её первый элемент wParameter-ом.
В следующей строке мы вызываем функцию InvalidateRect(), после чего выходим из WM_KEYDOWN. Первым параметром идёт – дескриптор окна, вторым – область будущего «затирания» окна (NULL – всё окно перерисовывается в WM_PAINT), третьим параметром идёт «затирание» фона (если TRUE, то стираем). При этом мы автоматически посылаем приложению message WM_PAINT и окно перерисовывается заново. Для чего это нужно?
Как мы помним в случаях сворачивания, перемещения окна вызывается WM_PAINT. Нам же это нужно сделать явно, то есть сделать окно недействительным, для того, чтобы сразу вывести значение нажатой клавиши на экран. Иначе она появится только тогда, когда мы начнём манипулировать окном.
Теперь возвратимся 65-й строке. В ней объявлен экземпляр класса HFONT, который отвечает за шрифт, его размер и другие премудрости. Он будет использоваться в WM_PAINT.
В 69-й строке есть обработчик сообщения WM_CREATE. Он срабатывает, когда создаётся окно, то есть вызывается функция CreateWindow(). На этом этапе решено создать дополнительное окно с сообщением для удобства (строки 70-72).
Наконец, обработчик WM_PAINT. С 75-й по 77-ю строки происходит вызов функций контекста устройства (описывалось в статье).
А с 78-й по 82-ю строки вызывается функция CreateFont(). С её помощи мы меняем шрифт, и размер буквы. Вот её описание:
?
HFONT CreateFont(int, // высота шрифта int, // ширина символов int, // угол наклона букв int, // угол наклона строки int, // толщина букв («жирность») DWORD, // курсив DWORD, // подчеркивание DWORD, // перечеркивание DWORD, // набор символов DWORD, // точность вывода DWORD, // точность отсечения DWORD, // качество вывода DWORD, // шаг между буквами LPCTSTR // имя шрифта ); |
Шрифт выставлен Arial Bold – то есть Arial жирным. В строке 83 мы задаём контексту изменённые параметры шрифта. С 84-й по 85-ю строки ничего нового. Мы вводим на экран полученный идентификатор клавиши, преобразованный в тип char. В функции DrawText() его нужно преобразовать к типу LPCWSTR, что она и требует.
Результат работы программы при вводе буквы «с» такой:
Для начала убедитесь, что Вы разбираетесь в выделении памяти с помощью функции alloc (malloc), free, с помощью операторов new, delete и понимаете функцию преобразованию itoa().
Рассмотрим листинг, представленный ниже:
?
LRESULT CALLBACK WindowProcess(HWND hWindow, UINT uMessage, WPARAM wParameter, LPARAM lParameter) { HDC hDeviceContext; PAINTSTRUCT paintStruct; RECT rectPlace; HFONT hFont; static PTCHAR text; static int size = 0; switch (uMessage) { case WM_CREATE: text=(PTCHAR)GlobalAlloc(GPTR,50000*sizeof(TCHAR)); break; case WM_PAINT: hDeviceContext = BeginPaint(hWindow, &paintStruct); GetClientRect(hWindow, &rectPlace); SetTextColor(hDeviceContext, NULL); hFont=CreateFont(50,0,0,0,0,0,0,0, DEFAULT_CHARSET, 0,0,0,VARIABLE_PITCH, "Arial Bold"); SelectObject(hDeviceContext,hFont); if(wParameter != VK_RETURN) DrawText(hDeviceContext, (LPCSTR)text, size, &rectPlace, DT_SINGLELINE|DT_CENTER|DT_VCENTER); EndPaint(hWindow, &paintStruct); break; case WM_CHAR: switch(wParameter) { case VK_RETURN: size=0; break; default: text[size]=(char)wParameter; size++; break; } InvalidateRect(hWindow, NULL, TRUE); break; case WM_DESTROY: PostQuitMessage(NULL); GlobalFree((HGLOBAL)text); break; default: return DefWindowProc(hWindow, uMessage, wParameter, lParameter); } return NULL; } |
Результат после ввода CppStudio.com будет таким:
Код для функции WinMain не приводится, так как он не менялся с предыдущих уроков.
Данная программа позволяет вводить текст по мере возможности и стирать его клавишей ENTER.
Наверное, Вы заметили, что в программе в предыдущем уроке для считывания нажатой клавиши мы использовали message WM_KEYDOWN, а здесь что-то новое — WM_CHAR.
Отличительная особенность в том, что WM_KEYDOWNнужен для обработки специальных клавиш типа shift, ctrl и т.п., а WM_CHAR– отвечает за обработку символов. Обычно они работают вместе для комбинаций клавиш и вызывают друг друга. В этом Вы убедитесь, когда мы будем разбирать работу текстового редактора.
По умолчанию в MVS используется Юникод. Его отключение производится следующим образом: заходим в свойства проекта
и отключаем Юникод, нажав «Использовать многобайтовую кодировку».
После того, как Вы это сделаете, перед строками не нужно будет писать L, и представленный код не будет иметь ошибок. По этой причине в программе прошлого урока было не правильное отображение некоторых символов.
Теперь второе отличие: мы можем вводить текст (примерно до 50 кБ), который сохранится в буфере.
Конструкция создания, использования, удаления буфера выглядит так:
?
static PTCHAR text; text=(PTCHAR)GlobalAlloc(GPTR,50000*sizeof(TCHAR)); if() { //.... // заполняем буфер информацией, используем её, где нам нужно //..... GlobalFree((HGLOBAL)text); } |
Она аналогична alloc() и free() и её смысл абсолютно такой же.
PTCHAR — указатель на тип TCHAR.
GPTR — режим выделения памяти (в данном случае фиксированное)
HGLOBAL — тип возвращаемого значения функции GlobalAlloc()
Третье достоинство нашей программы — возможность стирать текст (строки 36-38).
В случае нажатия клавиши ENTER – мы делаем окно не действительным с помощью функции InvalidateRect() (строка 44), тем самым вызываем сообщение WM_PAINT. В нём прописано, что если параметр wParameter был равен VK_RETURN (то есть ENTER), то мы перерисовываем окно и не вызываем функцию DrawText().
И, как и обещалось ранее, добавим в функцию таймер и некоторые другие особенности.
?
static int sec = 0; TCHAR workTime[10]; //... switch (wParameter) { case WM_CREATE: SetTimer(hWindow, 1, 1000, NULL); //... SetForegroundWindow(hWindow); break; case WM_CHAR: //... case VK_BACK: if(size!=0) size--; break; case WM_TIMER: sec++; break; case WM_DESTROY: KillTimer(hWindow, 1); _itoa(sec, workTime, 10); MessageBox(NULL, (LPCSTR)workTime, "Время работы программы (сек.):", MB_ICONASTERISK|MB_OK); //... break; } |
Добавьте в соответствующие места программы выше представленный код.
Функция SetTimer() создаёт таймер. Первый параметр — дескриптор окна, третий — интервал срабатывания WM_TIMER в миллисекундах, второй — количество вызовов WM_TIMER в заданный интервал времени. Четвёртый параметр — нам не нужен.
В сообщении WM_TIMER мы увеличиваем sec на единицу.
Функция KillTimer() — удаляет таймер. Параметры те же, что и в SetTimer().
Чтобы отобразить время работы программы, в WM_DESTROY мы преобразовываем int в TCHAR массив при помощи функции _itoa, выводим строку на экран, удаляем таймер и освобождаем память, выделенную под буфер.
Функция SetForegroundWindow(HWND) – делает окно активным. Например, если Вы находитесь на сайте CppStudio.com и при этом идёт компиляция данной программы, это окно появится поверх браузера с фокусом для ввода.
Для возможности удаления одного или нескольких символов добавлен обработчик VK_BACK– нажатие клавиши backspace. Если size не равен нулю (то есть не был нажат ENTER), мы уменьшаем его на единицу и последний элемент при обновлении окна не отображается.
В результате, при закрытии окна, мы получим такое сообщение:
ЛИТЕРАТУРА
1. Побегайло А. Системное программирование в Windows. – СПб.: БХВ-Петербург, 2006
2. Лав Р. Linux. Системное программирование. – СПб.: Питер, 2008
3. Несвижский В. Программирование аппаратных средств в Windows. - СПб.: БХВ-Петербург, 2008
4. Джонсон М. Харт. Системное программирование в среде Win32. M.: Издательский дом «Вильямс», 2001
5. Джеффри Рихтер. Windows. Создание эффективных Win32-приложений с учетом специфики 64-разрядной версии Windows/ Пер. с англ. — 4-е изд. — СПб.: Питер; М.: Издательство «Русская Редакция»; 2008
6. Ал Вильямс. Системное программирование в Windows 2000. - СПб.: Питер, 2001
7. Румянцев И.В. Азбука программирования в Win32 API. – М.: Горячая линия – телеком, 2001