Как перейти на следующую строку в файле c
Перейти к содержимому

Как перейти на следующую строку в файле c

  • автор:

C. Переход на следующую строку.

Здравствуйте.
Есть файл с последовательным доступом (текстовый), из которого нужно последовательно с каждой строки считывать какие-то данные.
Как перевести «курсор» на следующую строку? Размер текущей строки не задается, т.е. могут подсунуть любой.
Например, есть такой файл:

4 5 4 2 1
7 4 1 2 1 7 5 4
2 4 2
4 5 4 1 2
1 4

Просто fscanf(in, «\n%d», &Deck[c].K) в цикле все равно заглатывает числ а в 1й строке, а не по 1му столбцу.

Переход на новую строчку в файле (СИ)

Мне надо записывать в конец каждой строки файла символ. Так вот, как после записи переходить на следующую строчку файла?

Отслеживать

222k 15 15 золотых знаков 120 120 серебряных знаков 234 234 бронзовых знака

задан 22 апр 2017 в 14:26

143 1 1 золотой знак 1 1 серебряный знак 7 7 бронзовых знаков

Добавлять еще один символ к строке или заменять последний? Если заменять, то ничего делать не надо. После перезаписи строки просто читаете следующую. Если добавлять, то пишите все в новый файл, а потом переименуйте его в старый.

22 апр 2017 в 15:08

Нужно именно добавлять символ в конец строки. А без создания нового файла никак нельзя?

Как перейти на следующую строку в файле c

Операция чтения-записи всегда производится с текущей позиции в потоке. При открытии потока в режимах 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

Как на Си реализовать ввод в файл с новой строки?

P.S. Такими формулировками вопросов можно же людям весь мозг сломать. И вообще это в Development должно быть.

xaizek ★★★★★
( 04.11.17 16:43:28 MSK )
anonymous
( 04.11.17 16:44:57 MSK )

#include #include #include int main(void) < FILE *fp = NULL; size_t filesize = 0; char *filecontents = NULL; const char *strfilewrite = "lor is a wonderful site"; // разумное чтение fp = fopen("file.txt", "r"); if (fp == NULL) < fprintf(stderr, "open file error\n"); return -1; >fseek(fp, 0L, SEEK_END); filesize = ftell(fp); fseek(fp, 0L, SEEK_SET); filecontents = (char *) malloc((filesize +1) * sizeof(char)); if (filecontents == NULL) < fprintf(stderr, "mem alloc error\n"); return -1; >fread(filecontents, sizeof(char), filesize, fp); *(filecontents + filesize) = '\0'; fprintf(stdout, "%s\n", filecontents); free(filecontents); fclose(fp); // разумная запись fp = fopen("file.txt", "a+"); fwrite(strfilewrite, sizeof(char), strlen(strfilewrite), fp); fclose(fp); return 0; >

как-то так.. вне проверял, тут печатал.

cherry
( 05.11.17 13:53:22 MSK )
Ответ на: комментарий от xaizek 04.11.17 16:43:28 MSK

И вообще это в Development должно быть.

Может, он ядро переписывает, бгг.

Virtuos86 ★★★★★
( 05.11.17 13:55:36 MSK )
Ответ на: комментарий от cherry 05.11.17 13:53:22 MSK

 // разумная запись fp = fopen("file.txt", "a+"); if (fp == NULL) < // забыл проверочку. fprintf(stderr, "open file error\n"); return -1; >fwrite(strfilewrite, sizeof(char), strlen(strfilewrite), fp); fclose(fp);

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

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