C++. Сборник рецептов - [141]

Шрифт
Интервал

Решение

Используйте файловые потоки С++, определенные в >, для копирования одного потока в другой. Пример 10.9 показывает, как можно скопировать поток с помощью буфера

Пример 10.9. Копирование файла

>#include

>#include


>const static int BUF_SIZE = 4096;


>using std::ios_base;


>int main(int argc, char** argv) {

> std::ifstream in(argv[1],

>  ios_base::in | ios_base::binary);  // Задается двоичный режим, чтобы

> std::ofstream out(argv[2],          // можно было обрабатывать файлы с

>  ios_base::out | ios_base::binary), // любым содержимым

> // Убедитесь, что потоки открылись нормально...

> char buf[BUF_SIZE];

> do {

>  in.read(&buf[0], BUF_SIZE);      // Считать максимум n байт в буфер,

>  out.write(&buf[0], in.gcount()); // затем записать содержимое буфера

> } while (in.gcount() > 0);        // в поток вывода.

> // Проверить наличие проблем в потоках...

> in.close();

> out.close();

>}

Обсуждение

Можно посчитать, что копирование файла — это простая операция чтения из одного потока и записи в другой поток. Однако библиотека потоков C++ достаточно большая, и существует несколько различных способов чтения и записи потоков, поэтому надо обладать некоторыми знаниями об этой библиотеке, чтобы избежать ошибок, снижающих производительность этой операции.

Пример 10.9 работает быстро, потому что используется буферизация ввода-вывода. Функции >read и >write оперируют сразу всем содержимым буфера вместо посимвольного копирования, когда в цикле считывается символ из потока ввода в буфер и затем записывается в поток вывода. При их выполнении не делается никакого форматирования, подобного тому, которое выполняется операторами сдвига влево и вправо, что ускоряет выполнение операции. Кроме того, поскольку потоки работают в двоичном режиме, не надо специально обрабатывать символы EOF. В зависимости от используемого вами оборудования, ОС и т.д. вы получите различный результат при различных размерах буфера. Экспериментально вы можете найти наилучшие параметры для вашей системы

Однако можно добиться большего. Все потоки C++ уже буферизуют данные при их чтении и записи, поэтому в примере 10.9 фактически выполняется двойная буферизация. Поток ввода имеет свой собственный внутренний буфер потока, который содержит символы, прочитанные из исходного файла, но еще не обработанные с помощью >read, >operator<<, >getc или любых других функций-членов, а поток вывода имеет буфер, который содержит вывод, записанный в поток, но не в «пункт назначения» (в случае применения >ofstream это файл, но могла бы быть строка, сетевое соединение и кто знает, что еще). Поэтому лучше всего обеспечить непосредственный обмен данных буферов. Вы это можете сделать с помощью оператора >operator<<, который работает иначе с буферами потоков. Например, вместо цикла >do/while приведенного в примере 10.9, используйте следующий оператор.

>out << in.rdbuf();

Не следует размещать этот оператор в теле цикла, замените весь цикл одной строкой. Это выглядит немного странно, поскольку обычно оператор >operator<< говорит, «возьмите правую часть и передайте ее в поток левой части», однако, поверьте мне, эта запись имеет смысл, >rdbuf возвращает буфер потока ввода, а реализация >operator<<, принимающая буфер потока справа, считывает каждый символ буфера ввода и записывает его в буфер вывода. Когда буфер ввода заканчивается, он «знает», что должен заново заполнить себя данными из реального источника, a >operator<< ведет себя не лучше.

Пример 10.9 показывает, как можно скопировать содержимое файла, но ваша ОС отвечает за управление файловой системой, которая осуществляет копирование, так почему бы не предоставить право ОС сделать эту работу? В большинстве случаев на это можно ответить, что прямой вызов программного интерфейса ОС, конечно, не является переносимым решением. Библиотека Boost Filesystem скрывает от вас множество зависящих от ОС программных интерфейсов, предоставляя функцию >copy_file, которая выполняет системные вызовы ОС для той платформы, для которой она компилируется. Пример 10.10 содержит короткую программу, которая копирует файл из одного места в другое.

Пример 10.10. Копирование файла при помощи Boost

>#include

>#include

>#include

>#include


>using namespace std;

>using namespace boost::filesystem;


>int main(int argc, char** argv) {

> // Проверка параметров...

> try {

>  // Преобразовать аргументы в абсолютные пути, используя «родное»

>  // форматирование

>  path src = complete(path(argv[1], native));

>  path dst = complete(path(argv[2], native));

>  copy_file(src, dst);

> } catch (exception& e) {

>  cerr << e.what() << endl;

> }

> return(EXIT_SUCCESS);

>}

В этой небольшой программе все же имеется несколько ключевых вопросов, которые необходимо пояснить, поскольку другие рецепты данной главы используют библиотеку Boost Filesystem. Во первых, центральным компонентом библиотеки Boost Filesystem является класс >path, описывающий независимым от ОС способом путь к файлу или каталогу. Вы можете создать >path, используя как переносимый тип строки, так и специфичный для конкретной ОС. В примере 10.10 я создаю путь


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


Фундаментальные алгоритмы и структуры данных в Delphi

Книга "Фундаментальные алгоритмы и структуры данных в Delphi" представляет собой уникальное учебное и справочное пособие по наиболее распространенным алгоритмам манипулирования данными, которые зарекомендовали себя как надежные и проверенные многими поколениями программистов. По данным журнала "Delphi Informant" за 2002 год, эта книга была признана сообществом разработчиков прикладных приложений на Delphi как «самая лучшая книга по практическому применению всех версий Delphi».В книге подробно рассматриваются базовые понятия алгоритмов и основополагающие структуры данных, алгоритмы сортировки, поиска, хеширования, синтаксического разбора, сжатия данных, а также многие другие темы, тесно связанные с прикладным программированием.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.


Как пасти котов. Наставление для программистов, руководящих другими программистами

«Как пасти котов» – это книга о лидерстве и руководстве, о том, как первое совмещать со вторым. Это, если хотите, словарь трудных случаев управления IT-проектами. Программист подобен кошке, которая гуляет сама по себе. Так уж исторически сложилось. Именно поэтому так непросто быть руководителем команды разработчиков. Даже если вы еще месяц назад были блестящим и дисциплинированным программистом и вдруг оказались в роли менеджера, вряд ли вы знаете, с чего надо начать, какой выбрать стиль руководства, как нанимать и увольнять сотрудников, проводить совещания, добиваться своевременного выполнения задач.