Копирование файла на си
I search for a good way to copy a file (binary or text). I've written several samples, everyone works. But I want hear the opinion of seasoned programmers.
I missing good examples and search a way which works with C++.
ANSI-C-WAY
POSIX-WAY (K&R use this in "The C programming language", more low-level)
KISS-C++-Streambuffer-WAY
COPY-ALGORITHM-C++-WAY
OWN-BUFFER-C++-WAY
LINUX-WAY // requires kernel >= 2.6.33
Environment
- GNU/LINUX (Archlinux)
- Kernel 3.3
- GLIBC-2.15, LIBSTDC++ 4.7 (GCC-LIBS), GCC 4.7, Coreutils 8.16
- Using RUNLEVEL 3 (Multiuser, Network, Terminal, no GUI)
- INTEL SSD-Postville 80 GB, filled up to 50%
- Copy a 270 MB OGG-VIDEO-FILE
Steps to reproduce
Results (CPU TIME used)
Filesize doesn't change.
sha256sum print the same results.
The video file is still playable.
Questions
- What method would you prefer?
- Do you know better solutions?
- Do you see any mistakes in my code?
Do you know a reason to avoid a solution?
FSTREAM (KISS, Streambuffer)
I really like this one, because it is really short and simple. As far is I know the operator
Update 1
I changed the source in all samples in that way, that the open and close of the file descriptors is include in the measurement of clock(). Their are no other significant changes in the source code. The results doesn't changed! I also used time to double-check my results.
Update 2
ANSI C sample changed: The condition of the while-loop doesn't call any longer feof() instead I moved fread() into the condition. It looks like, the code runs now 10,000 clocks faster.
Measurement changed: The former results were always buffered, because I repeated the old command line rm to.ogv && sync && time ./program for each program a few times. Now I reboot the system for every program. The unbuffered results are new and show no surprise. The unbuffered results didn't changed really.
If i don't delete the old copy, the programs react different. Overwriting a existing file buffered is faster with POSIX and SENDFILE, all other programs are slower. Maybe the options truncate or create have a impact on this behaviour. But overwriting existing files with the same copy is not a real world use-case.
Performing the copy with cp takes 0.44 seconds unbuffered und 0.30 seconds buffered. So cp is a little bit slower than the POSIX sample. Looks fine for me.
Maybe I add also samples and results of mmap() and copy_file() from boost::filesystem.
Всем привет. Нужна помощь в написании программы на языке си,которая создавала бы файл - копию заданного файла, а имя файла указать в аргументе main. Спасибо.
Копирование одного текстового файла в другой, используя посимвольное, построчное и поблочное копирование
Здраствуйте, у меня такая проблемма мне надо обеспечить копирование одного текстового файла в.
Копирование файла, используя имена исходного и копируемого файла как аргументы командной строки
Напишите программу копирования файла, которая использует имена исходного файла и копируемого файла.
Копирование файла
Всем привет. Стало интересно, да и в целом нужно написать программу на языке си,которая создавала.
Решение
Привет, а этот вариант программы не сложный? Просто смотрю и не понимаю некоторых вещей, эту задачку нужно на 1 курсе
Добавлено через 2 минуты
Можно это как-то сделать проще? Но в любом случае - огромное спасибо.
Нашёл на просторах интернета, но вообще в этом не уверен, но в целом код вроде бы понятный. А в твоё коде,я даже не знаю некоторых функций, а также можешь пожалуйста сказать за что отвечают цифры после define. Ещё раз спасибо
Добавлено через 10 минут
А вот вариант вообще без проверок. При неправильном использовании программы, она может натворить дел.
Копирование бинарного файла
Существует-ли какая-то функция для копирования бинарного файла или придется каждую структуру.
Копирование содержимого файла fname1 в fname2
Программа была написана, но, по непонятной причине в файл записывает другие значения, нежели были.
Копирование данных из первого файла во второй
Подскажите, пожалуйста, в чем ошибка. Не копирует данные из первого файла во второй, чтоб можно.
Копирование строк из одного файла в другой
Здравствуйте. Разбираюсь с копированием текста из одного файла OUT в другой файл IN. Есть.
Копирование содержимого одного файла в другой
Всем доброго времени суток. Заранее извиняюсь за глупый вопрос я еще новичок. Вот решаю одну.
Прекрасно копирует текст, но возникают проблемы с .EXE, .JPG, .DOC и т.д.
Вопрос - почему и насколько сложно решается эта проблема?
P.S.: параметр "b", в fopen - не помогает.
Программа для копирования файлов: копируется только первый символ
Доброго время суток, пытаюсь создать программу для копирования файлов. Проблема состоит в том что.
Программа для копирования входного потока в выходной
/*программа печатающая ввод на вывод и вместо нескольких пробелов подряд оставляющая только один.
Не работает программа копирования содержимое одного текстового файла в другой
Из файла считывает, но новый файл не файл не создаётся. Задание:Скопировать содержимое одного.
Программа для копирования входного потока в выходной с заменой каждой строки
Программа для копирования входного потока в выходной с заменой каждой строки, состоящей из одного.
Считывает твоя программа символ, равный EOF, после чего завершается. Читай не до EOF а до конца файла (по размеру, всмысле, смотри).
Ну, насколько я помню, далеко не везьде EOF определён, как -1. Если он будет положителным, int c не поможет.
этот момент объясняется в K&R2 и getc() возвращает также int, то есть у неё никак 255 не станет равно -1
насколько я помню не везде -1, но везде отрицательный. этакая гарантия от совпадения с кодом символа.
Чёрт. Да назовите хоть один компилятор в какой-нибудь системе, где EOF != -1 Ни разу в жизни не встречал!
Спасибо, но я не знаком пока с С++.
Спасибо, сейчас попробую использовать!
Спасибо, чуть позже разберу и ваш пример
Добавлено через 36 минут
Вот написал простой код заново, как-то он странно добавляет лишний текст в новый файл иногда. Более того, даже если итоговый размер файлов совпадает - новый файл становится бракованным (картинка не открывается, ехе тоже и т.д.). Сравнение хэшов файлов так же говорит об их различии, не смотря на идентичный размер
Ой! Спасибо! Оно работает!
Да, а насчёт проверять. до вашего примера мне далеко, конечно, но постараюсь
Вопрос - разве параметр fopen "b" не используется только для бинарных файлов?
Скажите пожалуйста, а вот в двух словах, чем программа, написанная вами, копирующая файл с использованием буфера, лучше этого варианта?
И пара вопросов по ней:
- зачем char buf[] должен быть unsigned?
- и что такое BUF_LEN в:
параметр "b" в fopen() нужен для того, чтобы символ '\n' не преобразовывался в последовательность '\r''\n'. Если Вы копируете картинки/программы, содержимое файла без этого параметра будет искажаться.
Скажите пожалуйста, а вот в двух словах, чем программа, написанная вами, копирующая файл с использованием буфера, лучше этого варианта?
размер буфера 512 взят не с потолка - это размер блока на диске. Чтение/запись происходят значительно быстрее, если читать/писать не по одному символу или какому-то абстрактному количеству символов, а порциями, кратными размеру блока. На самом деле функции getc()/putc() и иже с ними тоже не по одному символу читают/пишут - они используют собственные буфера, но действий всё равно значительно больше получается.
Перечитайте мануал к функциям fread()/fwrite(): первый параметр - буфер, второй - размер одного элемента, третий - количество элементов, четвёртый - поток (файл). Возвращаемое значение - количество прочитанных/записанных элементов.
Чтение/запись происходят значительно быстрее, если читать/писать не по одному символу или какому-то абстрактному количеству символов, а порциями, кратными размеру блока. На самом деле функции getc()/putc() и иже с ними тоже не по одному символу читают/пишут - они используют собственные буфера, но действий всё равно значительно больше получается.
Скажите, а можно как-то узнать время выполнения программы в миллисекундах? Хотелось бы скорость сравнить
Просто time() в секундах считает, слишком грубо, хотя для файлов больших размеров может и её хватит.
Скажите, как на чистом СИ осуществить максимально быстрое копирование файлов? Я пишу небольшую программку для микроконтроллера Vinculum II. Там есть какая-то своя операционная система, файловая система, но, в API этого микроконтроллера я не нашел функцию копирования файлов. Потому копировал его посимвольно, используя fgetc() и fputc(), но это очень и очень медленно, для копирования файла размером 5КБ потребовалось около 20 секунд, что, естественно, меня не устраивает. Подскажите, как можно ускорить этот процесс.
Копирование файла, если имя старого и нового файлов передается в командной строке
..помогите. даже не знаю с чего начать. лаба по ос..работаем в putty..а задание такое.. операции.
Копирование одного текстового файла в другой, используя посимвольное, построчное и поблочное копирование
Здраствуйте, у меня такая проблемма мне надо обеспечить копирование одного текстового файла в.
Копирование: Ввод имени папки и копирование из нее файлов
Доброго времени суток! Реально ли реализовать подобное с помощью bat ? Знаю, что можно создать.
Копирование файлов из разных каталогов в каталоги с именами, соответствующими номерам в именах файлов
Добрый день! Помогите решить проблему. Есть семь папок (cam_1, cam_2, cam_3 и.т.д) с фотографиями.
Так, попробовал fread() и fwrite()все работает отлично, НО в начале каждого блока почему-то пишется какая-то непонятная последовательность из 4-ех символов и она, эта последовательность, затирает 4 байта полезной информации.
Вот то, как я реализовывал копирование
на функцию fsAttach() особого внимания не обращайте, она лишь переключает интерфейсы на микроконтроллере.
вот что получается в выходном файле
здесь легко можно увидеть, что в начале каждого блока из 512 байт стоит последовательность °(ј*, которой там быть не должно.
сами по себе fread и fwrite точно ничего не пишут лишнего, это ж не псевдоЮникод с BOM. наверна, твой контроллер каким-то BOM и балуется
Там, в моем листинге, есть пара закомментированных строк, именно так я копировал файл в самом начале, я говорил об этом в своем первом посте, так вот, при посимвольном копировании в файл пишется все то, что и должно туда писаться и никаких непонятных закорючек там нет. Хотелось бы знать почему. Ведь если они были в одном месте, то, я так думаю, должны быть и в другом.
Неправильное условие, в принципе, для любого способа считывания файла. feof нужно вызывать непосредственно после попытки чтения из файла.
Следуя вашему совету немного изменил цикл чтения:
но это абсолютно ничего не дало. При попытке поставить спецификатор "b" программа вообще отказывалась работать, что, скорее всего связано с тем что на моем контроллере стоит какая-то непонятная операционка, a спецификатор "b", на сколько я знаю используется только в windows.
Но я заметил одну особенность. Я поменял у файла спецификатор "w+" на "w" и выходной файл несколько изменился:
Видно, что изменилась последовательность этих закорючек. С чем это может быть связано. Ума не приложу.
Добавлено через 3 часа 8 минут
Ребят, кароч я олень =) Нашел свою ошибку, если кому интересно:
Теги: Текстовые файлы, fopen, fclose, feof, setbuf, setvbuf, fflush, fgetc, fprintf, fscanf, fgets, буферизированный поток, небуферизированный поток.
Примеры
1. В одном файле записаны два числа - размерности массива. Заполним второй файл массивом случайных чисел.
2. Пользователь копирует файл, при этом сначала выбирает режим работы: файл может выводиться как на консоль, так и копироваться в новый файл.
3. Пользователь вводит данные с консоли и они записываются в файл до тех пор, пока не будет нажата клавиша esc. Проверьте программу и посмотрите. как она себя ведёт в случае, если вы вводите backspace: что выводится в файл и что выводится на консоль.
4. В файле записаны целые числа. Найти максимальное из них. Воспользуемся тем, что функция fscanf возвращает число верно прочитанных и сопоставленных объектов. Каждый раз должно возвращаться число 1.
Другое решение считывать числа, пока не дойдём до конца файла.
5. В файле записаны слова: русское слово, табуляция, английское слово, в несколько рядов. Пользователь вводит английское слово, необходимо вывести русское.
Файл с переводом выглядит примерно так
солнце sun
карандаш pen
шариковая ручка pencil
дверь door
окно windows
стул chair
кресло armchair
и сохранён в кодировке cp866 (OEM 866). При этом важно: последняя пара cлов также заканчивается переводом строки.
Алгоритм следующий - считываем строку из файла, находим в строке знак табуляции, подменяем знак табуляции нулём, копируем русское слово из буфера, копируем английское слово из буфера, проверяем на равенство.
6. Подсчитать количество строк в файле. Будем считывать файл посимвольно, считая количество символов '\n' до тех пор, пока не встретим символ EOF. EOF – это спецсимвол, который указывает на то, что ввод закончен и больше нет данных для чтения. Функция возвращает отрицательное значение в случае ошибки.
ЗАМЕЧАНИЕ: EOF имеет тип int, поэтому нужно использовать int для считывания символов. Кроме того, значение EOF не определено стандартом.
Всё ещё не понятно? – пиши вопросы на ящик
Ошибка открытия файла
Если вызов функции fopen прошёл неудачно, то она возвратит NULL. Ошибки во время работы с файлами встречаются достаточно часто, поэтому каждый раз, когда мы окрываем файл, необходимо проверять результат работы
Проблему вызывает случай, когда открывается сразу несколько файлов: если один из них нельзя открыть, то остальные также должны быть закрыты
В простых случаях можно действовать влоб, как в предыдущем куске кода. В более сложных случаях используются методы, подменяющиее RAII из С++: обёртки, или особенности компилятора (cleanup в GCC) и т.п.
Работа с текстовыми файлами
Р абота с текстовым файлом похожа работу с консолью: с помощью функций форматированного ввода мы сохраняем данные в файл, с помощью функций форматированного вывода считываем данные из файла. Есть множество нюансов, которые мы позже рассмотрим. Основные операции, которые необходимо проделать, это
- 1. Открыть файл, для того, чтобы к нему можно было обращаться. Соответственно, открывать можно для чтения, записи, чтения и записи, переписывания или записи в конец файла и т.п. Когда вы открываете файл, может также произойти куча ошибок – файла может не существовать, это может быть файл не того типа, у вас может не быть прав на работу с файлом и т.д. Всё это необходимо учитывать.
- 2. Непосредственно работа с файлом - запись и чтение. Здесь также нужно помнить, что мы работаем не с памятью с произвольным доступом, а с буферизированным потоком, что добавляет свою специфику.
- 3. Закрыть файл. Так как файл является внешним по отношению к программе ресурсом, то если его не закрыть, то он продолжит висеть в памяти, возможно, даже после закрытия программы (например, нельзя будет удалить открытый файл или внести изменения и т.п.). Кроме того, иногда необходимо не закрывать, а "переоткрывать" файл для того, чтобы, например, изменить режим доступа.
Кроме того, существует ряд задач, когда нам не нужно обращаться к содержимому файла: переименование, перемещение, копирование и т.д. К сожалению, в стандарте си нет описания функций для этих нужд. Они, безусловно, имеются для каждой из реализаций компилятора. Считывание содержимого каталога (папки, директории) – это тоже обращение к файлу, потому что папка сама по себе является файлом с метаинформацией.
Иногда необходимо выполнять некоторые вспомогательные операции: переместиться в нужное место файла, запомнить текущее положение, определить длину файла и т.д.
Для работы с файлом необходим объект FILE. Этот объект хранит идентификатор файлового потока и информацию, которая нужна, чтобы им управлять, включая указатель на его буфер, индикатор позиции в файле и индикаторы состояния.
Объект FILE сам по себе является структурой, но к его полям не должно быть доступа. Переносимая программа должна работать с файлом как с абстрактным объектом, позволяющим получить доступ до файлового потока.
Создание и выделение памяти под объект типа FILE осуществляется с помощью функции fopen или tmpfile (есть и другие, но мы остановимся только на этих).
Функция fopen открывает файл. Она получает два аргумента – строку с адресом файла и строку с режимом доступа к файлу. Имя файла может быть как абсолютным, так и относительным. fopen возвращает указатель на объект FILE, с помощью которого далее можно осуществлять доступ к файлу.
Например, откроем файл и запишем в него Hello World
Функция fopen сама выделяет память под объект, очистка проводится функцией fclose. Закрывать файл обязательно, самостоятельно он не закроется.
Функция fopen может открывать файл в текстовом или бинарном режиме. По умолчанию используется текстовый. Режим доступа может быть следующим
Тип | Описание |
---|---|
r | Чтение. Файл должен существовать. |
w | Запись нового файла. Если файл с таким именем уже существует, то его содержимое будет потеряно. |
a | Запись в конец файла. Операции позиционирования (fseek, fsetpos, frewind) игнорируются. Файл создаётся, если не существовал. |
r+ | Чтение и обновление. Можно как читать, так и писать. Файл должен существовать. |
w+ | Запись и обновление. Создаётся новый файл. Если файл с таким именем уже существует, то его содержимое будет потеряно. Можно как писать, так и читать. |
a+ | Запись в конец и обновление. Операции позиционирования работают только для чтения, для записи игнорируются. Если файл не существовал, то будет создан новый. |
Если необходимо открыть файл в бинарном режиме, то в конец строки добавляется буква b, например “rb”, “wb”, “ab”, или, для смешанного режима “ab+”, “wb+”, “ab+”. Вместо b можно добавлять букву t, тогда файл будет открываться в текстовом режиме. Это зависит от реализации. В новом стандарте си (2011) буква x означает, что функция fopen должна завершиться с ошибкой, если файл уже существует. Дополним нашу старую программу: заново откроем файл и считаем, что мы туда записали.
Вместо функции fgets можно было использовать fscanf, но нужно помнить, что она может считать строку только до первого пробела.
fscanf(file, "%127s", buffer);
Также, вместо того, чтобы открывать и закрывать файл можно воспользоваться функцией freopen, которая «переоткрывает» файл с новыми правами доступа.
Функции fprintf и fscanf отличаются от printf и scanf только тем, что принимают в качестве первого аргумента указатель на FILE, в который они будут выводить или из которого они будут читать данные. Здесь стоит сразу же добавить, что функции printf и scanf могут быть без проблем заменены функциями fprintf и fscanf. В ОС (мы рассматриваем самые распространённые и адекватные операционные системы) существует три стандартных потока: стандартный поток вывода stdout, стандартный поток ввода stdin и стандартный поток вывода ошибок stderr. Они автоматически открываются во время запуска приложения и связаны с консолью. Пример
Буферизация данных
- 1) Если он заполнен
- 2) Если поток закрывается
- 3) Если мы явно указываем, что необходимо очистить буфер (здесь тоже есть исключения:)).
- 4) Также очищается, если программа завершилась удачно. Вместе с этим закрываются и все файлы. В случае ошибки выполнения этого может не произойти.
Форсировать выгрузку буфера можно с помощью вызова функции fflush(File *). Рассмотрим два примера – с очисткой и без.
Раскомментируйте вызов fflush. Во время выполнения откройте текстовый файл и посмотрите на поведение.
Буфер файла можно назначить самостоятельно, задав свой размер. Делается это при помощи функции
которая принимает уже открытый FILE и указатель на новый буфер. Размер нового буфера должен быть не меньше чем BUFSIZ (к примеру, на текущей рабочей станции BUFSIZ равен 512 байт). Если передать в качестве буфера NULL, то поток станет небуферизированным. Можно также воспользоваться функцией
- _IOFBF - полная буферизация. Данные записываются в файл, когда он заполняется. На считывание, буфер считается заполненным, когда запрашивается операция ввода и буфер пуст.
- _IOLBF - линейная буферизация. Данные записываются в файл когда он заполняется, либо когда встречается символ новой строки. На считывание, буфер заполняется до символа новой строки, когда запрашивается операция ввода и буфер пуст.
- _IONBF – без буферизации. В этом случае параметры size и buffer игнорируются.
Пример: зададим свой буфер и посмотрим, как осуществляется чтение из файла. Пусть файл короткий (что-нибудь, типа Hello, World!), и считываем мы его посимвольно
Видно, что данные уже находятся в буфере. Считывание посимвольно производится уже из буфера.
Функция int feof (FILE * stream); возвращает истину, если конец файла достигнут. Функцию удобно использовать, когда необходимо пройти весь файл от начала до конца. Пусть есть файл с текстовым содержимым text.txt. Считаем посимвольно файл и выведем на экран.
Всё бы ничего, только функция feof работает неправильно. Это связано с тем, что понятие "конец файла" не определено. При использовании feof часто возникает ошибка, когда последние считанные данные выводятся два раза. Это связано с тем, что данные записывается в буфер ввода, последнее считывание происходит с ошибкой и функция возвращает старое считанное значение.
Этот пример сработает с ошибкой (скорее всего) и выведет последний символ файла два раза.
Решение – не использовать feof. Например, хранить общее количество записей или использовать тот факт, что функции fscanf и пр. обычно возвращают число верно считанных и сопоставленных значений.
Читайте также: