Как вернуться в начало файла си
Перейти к содержимому

Как вернуться в начало файла си

  • автор:

Как вернуться в начало файла си

Операция чтения-записи всегда производится с текущей позиции в потоке. При открытии потока в режимах r и w указатель текущей позиции устанавливается на начальный байт потока. При открытии в режиме a указатель устанавливается на конец файла сразу за конечным байтом. И при выполнении операции чтения-записи указатель в потоке перемещается на новую позиции в соответствии с числом прочитанных или записанных байтов.

Однако вполне возможно, что нам потребуется считывать или записывать с какой-то определенной позиции в файле. Например, в айдиофайле в формате wav собственно звуковые данные расположены, начиная с 44 байта. И если, к примеру, мы хотим распознать звук из файла, что-то с ним сделать, то нам при считывании данных надо переместить указатель на соответствующую позицию.

В языке Си для управления позицией указателя в потоке применяется функция fseek() , которая имеет следующий синтаксис:

int fseek(указатель_на_поток, смещение, начало_отсчета);

Второй параметр этой функции — смещение представляет числовое значение типа long , которое указывает, на какое количество байт надо переместить указатель. Это значение может быть отрицательным, если необходимо в потоке вернуться назад на некоторое количество байт.

Третий параметр — начало_отсчета задает начальную позицию, относительно которой идет смещение. В качестве этого параметра мы можем использовать одну из встроенных констант, определенных в файле stdio.h :

  • SEEK_SET : имеет значение 0 и представляет начало файла
  • SEEK_CUR : имеет значение 1 и представляет текущую позицию в потоке
  • SEEK_END : имеет значение 2 и представляет конец файла

Если перемещение указателя было успешно выполнено, то функция fseek() возвращает 0, иначе она возвращает ненулевое значение.

Применим функцию fseek в программе:

#include void load(char *, int); void save(char *); int main(void) < // файл для записи и чтения char * filename = "data.txt"; // позиция, с которой начинается считывание int position = 6; save(filename); load(filename, position); return 0; >void load(char * filename, int position) < // буфер для считавания данных из файла char buffer[256]; // чтение из файла FILE *fp = fopen(filename, "r"); if(!fp) < printf("Error occured while opening file\n"); return; >// перемещаем указатель в файле на позицию position fseek(fp, position, SEEK_SET); // пока не дойдем до конца, считываем по 256 байт while((fgets(buffer, 256, fp))) < printf("%s", buffer); >fclose(fp); > void save(char * filename) < // строка для записи char * message = "Hello METANIT.COM!"; // запись в файл FILE *fp = fopen(filename, "w"); if(!fp) < printf("Error occured while opening file\n"); return; >// записываем строку fputs(message, fp); fclose(fp); printf("File has been written\n"); >

Здесь функция save() записывает в файл строку «Hello METANIT.COM!». Далее функция load() считывет данные из этой строки. Но считывает не сначала, а с позиции, которая передается через параметр position :

// перемещаем указатель в файле на позицию position fseek(fp, position, SEEK_SET);

Поскольку третий аргумент равен SEEK_SET , то указатель файла смещается к байту с индексом position. Соответственно далее функция fgets() будет считывать данные не с самого начала файла, а с позиции position:

while((fgets(buffer, 256, fp)))

Поскольку в данном случае в качестве позиции передается число 6, то в тексте файла будут пропущены первые 6 символов, и будет считана подстрока «METANIT.COM!»

ftell

Кроме функции fseek() мы можем использовать для управления позицией указателя еще пару функций:

  • long ftell(FILE *) : получает текущую позицию указателя
  • void rewind(FILE *) : указатель устанавливается на начало потока

Например, мы можем применять функцию ftell для вычисления длины файла в байтах:

#include int main(void) < FILE* fp = fopen("test.txt", "r"); if(!fp) // если не удалось открыть файл < printf("Error while opening file\n"); return -1; >// если удалось, открыть файл получаем его длину fseek(fp, 0, SEEK_END); // устанавливаем указатель на конец файл long size = ftell(fp); // получаем значение указателя относительно начала fclose(fp); // закрываем файл printf("File size: %ld bytes\n", size); >

В данном случае находим длину файла «text.txt», который располагается в папке программы. Само находждение длины разбивается на два этапа. Сначала помещаем указатель в файле на конец с помощью функции fseek() :

fseek(fp, 0, SEEK_END);

Затем с помощью функции ftell() вычисляем положение указателя относительно начала файла — фактически получаем размер файла в байтах

long size = ftell(fp);

Считывание определенной структуры из файла

Рассмотрим более сложный пример:

#include #include struct person < char name[20]; int age; >; int save(char * filename, struct person *st, int n); int load(char * filename); int main(void) < char * filename = "people.dat"; struct person people[] = < , , , >; int n = sizeof(people) / sizeof(people[0]); save(filename, people, n); load(filename); return 0; > // запись в файл массива структур int save(char * filename, struct person * st, int n) < char *c; // указатель для посимвольной записи данных // число записываемых байтов int size = n * sizeof(struct person); FILE * fp = fopen(filename, "wb"); if (!fp) < printf("Error occured while opening file\n"); return 1; >// записываем количество структур c = (char *)&n; for (int i = 0; i < sizeof(n); i++) < putc(*c++, fp); >// посимвольно записываем в файл все структуры c = (char *)st; for (int i = 0; i < size; i++) < putc(*c, fp); c++; >fclose(fp); return 0; > // загрузка из файла массива структур int load(char * filename) < char *c; // указатель на считывания очередного символа int n = sizeof(struct person); // сколько байт надо считать для структуры int index; // номер структуры из файла: printf("Enter user number: "); // ввод номера структуры scanf("%d", &index); FILE * fp = fopen(filename, "rb"); // открываем файл на чтение if (!fp) < printf("Error occured while opening file\n"); return 1; >// выделяем память для количества структур int *ptr_count = malloc(sizeof(int)); // считываем количество структур c = (char *)ptr_count; int m = sizeof(int); // сколько надо считать структур // пока не считаем m байт while (m > 0 && (*c = getc(fp))!=EOF) // сохраняем байт в выделенный блок для размера массива < c++; m--; >//получаем число элементов int count = *ptr_count; free(ptr_count); // освобождаем память // если номер запрощенной структуры меньше кол-ва структур if(index > count) < printf("User number out of range\n"); fclose(fp); return 1; >// получаем, на сколько байтов надо перемотать указатель относительно начала позиции int pos = (index-1) * n + 4; // перемещаем указатель на нужную позицию fseek(fp, pos, SEEK_SET); // выделяем память для считываемой структуры struct person * ptr = malloc(sizeof(struct person)); // устанавливаем указатель на начало блока памяти c = (char *)ptr; // после записи считываем посимвольно из файла while(n > 0 && (*c=getc(fp))!=EOF) < c++; n--; >// вывод считанных данных на консоль printf("%-10s %5d \n", ptr->name, ptr->age); free(ptr); fclose(fp); return 0; >

С помощью функции save в файл сохраняется массив структур. Затем в функции load считываем одну из структур по введенному номеру.

Для поиска нужной структуры вычисляем позицию:

int pos = (index-1) * n + 4;

Исходя из записи мы знаем, что первые 4 байта в файле отводятся под хранение количества структур, соответственно при чтении нам надо пропустить эти 4 байта.

Например, мы хотим получить первую структуру. По формуле получаем (index-1) * n + 4 = 4. То есть первая структура будет располагаться после 4-го байта. Аналогично вторая структура будет располагаться после n+4 байт, где n — это размер структуры.

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

// перемещаем указатель на нужную позицию fseek(fp, pos, SEEK_SET);

При последующей операции чтения с помощью функции getc() :

while(n > 0 && (*c=getc(fp))!=EOF)

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

Результат работы программы:

Input user number: 2 Alice 27

Стоит отметить, что для большей краткости здесь убрана проверка на наличие структуры по введенному номеру, так как пользователь может ввести число, которое превышает количество

Обновление структуры в файле

Мы можем использовать указатель в потоке не только для чтения, но и для записи данных. Например:

#include struct person < unsigned id; char name[10]; int age; >; void save(char*); void update_age(char*, int, int); int main() < char * filename = "people.bin"; save(filename); update_age(filename, 2, 33); // в структуре с устанавливаем age = 33 >void save(char* filename) < struct person people[] = < , , >; int size = sizeof(people[0]); // размер всего массива int count = sizeof(people) / size; // количество структур // запись файла FILE *fp = fopen(filename, "w"); // записываем массив структур fwrite(people, size, count, fp); fclose(fp); printf("%d people saved\n", count); > void update_age(char* filename, int id, int age) < // считывание файла, пока не найдем структуру с определенным id struct person p; // структура для чтения int size = sizeof(p); FILE* fp = fopen(filename, "r+"); // "r+" - открываем файл для изменения // считываем данные в структуру while(fread(&p, sizeof(p), 1, fp)==1) < // если нашли структуру с нужным id if(p.id == id) < p.age = age; // изменяем возраст fseek(fp, -1*size, SEEK_CUR); // перемещаем в потоке на один объект назад fwrite(&p, size, 1, fp); // записываем обновленную структуру break; // выходим из цикла >> rewind(fp); // перематываем файл назад // считываем по одной структуре и проверяем изменения while(fread(&p, sizeof(p), 1, fp) == 1) < printf("Id: %d \t Name: %s \t Age: %d \n", p.id, p.name, p.age); >fclose(fp); >

В функции update_age() обновляем возраст пользователя по определенному id. Для этого открываем файл с флагом «r+», то есть для чтения с измением.

FILE* fp = fopen(filename, "r+");

Затем считываем по одной структуре и проверяем id. Если id структуры равен запрошенному id, то изменяем возраст и перезаписываем структуру в файле:

if(p.id == id) < p.age = age; // изменяем возраст fseek(fp, -1*size, SEEK_CUR); // перемещаем в потоке на один объект назад fwrite(&p, size, 1, fp); // записываем обновленную структуру break; // выходим из цикла >

Для перезаписи перемещаемся в файле на начало структуры ( fseek(fp, -1*size, SEEK_CUR) ). Поскольку, когда мы считали структуру, указатель в файле указывает на следующую за ней структуру.

Поскольку id у структур уникальны, соответственно нам надо изменить только один объект, поэтому после изменения объекта выходим из цикла.

Чтобы до закрытия файла вывести в этой же функции все структуры из файла, перемещаем указатель в файле на начало с помощью функции rewind()

rewind(fp); // перематываем файл назад

Таким образом, структура с где изначально age был равен 27, изменит это значение age на 33. Консольный вывод программы:

3 people saved Id: 1 Name: Tom Age: 38 Id: 2 Name: Sam Age: 33 Id: 3 Name: Bob Age: 42

Вернуться в начало файла

Author24 — интернет-сервис помощи студентам

Как вернуться в начало программы.
Как сделать так, чтобы при наступления какого-либо условия программа прерывалась и начаналась.

Как вернуться в начало программы?
Собственно несколько дней назад начал изучать язык С++,добрался до темы switch,в общем и целом.

Как вернуться в начало цикла while?
У меня в коде такая структура while ( game == 1) //code// level = 2 while(game == 2 ).

Как вернуться в начало?
как мне сделать, что бы после одного перевода можно было дальше писать месяца? namespace.

56 / 50 / 11
Регистрация: 10.11.2010
Сообщений: 132

1 2 3 4 5
fstream file; file.open( . ); . . file.seekg(0);

Регистрация: 02.01.2012
Сообщений: 73
не работает

1 2 3 4
char c; while (File.get(c)) coutc; File.seekg(0); while (File.get(c)) coutc;

5498 / 4893 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
Флаг конца файла нужно сбросить:

1 2 3 4 5 6 7
char c; while (File.get(c)) cout  c; File.clear(); File.seekg(0); while (File.get(c)) cout  c;

56 / 50 / 11
Регистрация: 10.11.2010
Сообщений: 132

Лучший ответ

Сообщение было отмечено как решение

Решение

file.clear(); file.seekg(0);

забыл дописать, для того, чтобы корректно работала функция seekg(), необходимо сперва вызвать метод clear() — т.к. у нас достигается конец файла file.eof()

87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
Помогаю со студенческими работами здесь

Вернуться в начало программы
Что то я совсем запутался и никак немогу в указанном месте перейти в точку входа программы using.

Как вернуться в начало цикла?
Здравствуйте, пишу программу, которая по нажатию кнопок от 1 до 5 будет выводить определенный.

Как вернуться в начало условия if?
Здравствуйте,уважаемые. #!/usr/bin/python3 # -*- coding:utf-8 -*- io = input(‘Въезд(i) или.

Как вернуться в начало цикла
Есть ли команда которая возвращает в начало цикла? К примеру есть цикл do while в нем условие if.

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

Как вернуться в начало программы?
Здравствуйте, подскажите пожалуйста можно ли без использования цикла и метки вернуться к началу.

Или воспользуйтесь поиском по форуму:

Как перейти в начало текстового файла?

Author24 — интернет-сервис помощи студентам

Какую строку добавить в код, чтоб перейти в начало файла?

1 2 3 4 5 6
while (fin.get(ch)) { if (isdigit(ch)) ++num; }

94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:

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

Как добавить строку в начало текстового файла
Добрый день! Столкнулся с такой проблемой, вернее проблемкой. При выводе отчетных данных в.

Как найти начало и конец строки файла (текстового)
Здравствуйте! Как найти начало и конец строки файла (текстового). Спасибо

Как в начало каждой строки текстового файла вставить заданное слово?
как в txt в каждую строку перед первым словом в строке написать слово mod? пустых строк нет .

int fseek (FILE *stream, long offset, int origin)

Функция fseek() устанавливает указатель положения в файле, связанном со stream, в соответ­ствии со значениями offset и origin. Ее основное назначение — поддерживать операции ввода/ вывода по произвольному адресу. Аргумент offset — это выраженный в байтах сдвиг от позиции, определяемой origin, до новой позиции. Аргумент origin может принимать значения 0, 1 или 2, причем 0 означает начало файла, 1 — текущую позицию, а 2 — конец файла. В stdio.h определе­ны следующие макросы для origin

Имя Позиция origin
SEEK_SET Начало файла
SEEK_CUR Текущая позиция
SEEK_END Конец файла

В случае успеха fseek() возвращает 0. Ненулевое значение означает неудачу. С помощью fseek() можно переместить указатель положения в любую точку внутри файла и даже за его пределы после конца файла. Однако попытка установить указатель перед началом файла будет восприня­та как ошибка.

Функция fseek() сбрасывает флаг конца файла, связанный с указанным потоком. Кроме того, она обнуляет любую предыдущую ungetc() в том же потоке.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *