Как сравнить позиции счётчика байтов в открытом (fopen) бинарном файле? (код на Си)

Модератор: Модераторы разделов

Ответить
Аватара пользователя
жучара
Сообщения: 950
ОС: астралинукс

Как сравнить позиции счётчика байтов в открытом (fopen) бинарном файле?

Сообщение жучара »

Друзья! Ну то есть открываем файл на чтение, фиксируем счётчик байтов в какой-то позиции. Работаем-работаем-работаем- потом раз- нужно проверить, находится счётчик байтов на первоначальной позиции или нет. Как это сделать? Вот код на Си:

Код: Выделить всё

//p.c
#include <stdio.h>

int main ()
{
	FILE*  fp;

	//Вот я открыл файл и счётчик зафиксировал в переменной fpos_0
	fp = fopen ("test", "rb");
	fpos_t fpos_0;
	fgetpos (fp, &fpos_0);

	//Передвинул счётчик, снова зафиксировал в переменной fpos_1
	fseek (fp, 15, SEEK_SET);
	fpos_t fpos_1;
	fgetpos (fp, &fpos_1);

	//Как узнать, в первоначальном положении счётчик или нет?
	if (fpos_0 != fpos_1);
		
	return 0;
	
}

Shell

$ gcc p.c
p.c: In function ‘main’:
p.c:15:13: error: invalid operands to binary != (have ‘fpos_t’ and ‘fpos_t’)
15 | if (fpos_0 != fpos_1);
| ^~
$
Такие дела. Спасибо, кто откликнется. Debian 11.
P.S. С преобразованием типов, вот так:

Код: Выделить всё

if ((int)fpos_0 != (int)fpos_1);
тоже не компилится.
Последний раз редактировалось жучара 23.09.2022 15:18, всего редактировалось 1 раз.
Я просто читаю маны.
Спасибо сказали:
Аватара пользователя
жучара
Сообщения: 950
ОС: астралинукс

Re: Как сравнить позиции счётчика байтов в открытом (fopen) бинарном файле?

Сообщение жучара »

Всё, понял, fpos_t это структура

Код: Выделить всё

#ifndef _____fpos_t_defined
#define _____fpos_t_defined 1

#include <bits/types.h>
#include <bits/types/__mbstate_t.h>

/* The tag name of this struct is _G_fpos_t to preserve historic
   C++ mangled names for functions taking fpos_t arguments.
   That name should not be used in new code.  */
typedef struct _G_fpos_t
{
  __off_t __pos;
  __mbstate_t __state;
} __fpos_t;

#endif
Нужно сравнивать так:

Код: Выделить всё

if (fpos_0.__pos != fpos_1.__pos)
или я что-то не то делаю, в системные хидеры своими толстыми пальцами лезу.
Я просто читаю маны.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20792
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Как сравнить позиции счётчика байтов в открытом (fopen) бинарном файле?

Сообщение Bizdelnick »

жучара писал(а):
21.09.2022 19:27
или я что-то не то делаю, в системные хидеры своими толстыми пальцами лезу.
Именно. Всё, что начинается с __, трогать не следует. Это детали реализации, которые могут различаться на разных системах.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
жучара
Сообщения: 950
ОС: астралинукс

Re: Как сравнить позиции счётчика байтов в открытом (fopen) бинарном файле?

Сообщение жучара »

IMB писал(а):
22.09.2022 17:58
https://man7.org/linux/man-pages/man3/fseeko.3.html

или через https://man7.org/linux/man-pages/man2/lseek.2.html передав в него fileno(FILE *)
Что-то особо lseek не хочет соответствовать действительности. Открываю файл, двигаю счётчик, получаю смещение. В третий раз неправильное, должно быть 1 а выводит 60. Размер файла показываю.

Код: Выделить всё

//m.c
#include <stdio.h>
#include <unistd.h>

int main ()
{
	FILE*  fp;
 	int df;
	
	//Вот я открыл файл
	fp = fopen ("test", "rb");
	df = fileno (fp);
	if (df == -1)
	{
		printf ("Всё плохо\n");
	}

	//Смещение от начала файла будет класть в переменную x
	int x;

	//Сместились, смещение получили, вывели
	fseek (fp, 0, SEEK_CUR);
	x = lseek (df, 0, SEEK_CUR);
	printf ("x = %d\n", x);
	
	//Сместились, смещение получили, вывели
	fseek (fp, 1, SEEK_CUR);
	x = lseek (df, 0, SEEK_CUR);
	printf ("x = %d\n", x);

	//Сместились, смещение получили, вывели
	fseek (fp, 0, SEEK_CUR);
	x = lseek (df, 0, SEEK_CUR);
	printf ("x = %d\n", x);
	
	return 0;
	
}

Shell

$ gcc m.c
$ ./a.out
x = 0
x = 1
x = 60
$
$ ls -l test
-rw-r--r-- 1 user user 60 сен 23 20:35 test
$
Я просто читаю маны.
Спасибо сказали:
IMB
Сообщения: 2561
ОС: Debian

Re: Как сравнить позиции счётчика байтов в открытом (fopen) бинарном файле?

Сообщение IMB »

https://man7.org/linux/man-pages/man3/ftell.3.html
The ftell() function obtains the current value of the file position indicator for the stream pointed to by stream.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20792
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Как сравнить позиции счётчика байтов в открытом (fopen) бинарном файле?

Сообщение Bizdelnick »

А кто сказал, что можно мешать lseek c fseek? lseek — системный вызов, fseek — функция библиотеки буферизованного ввода-вывода. То есть fseek может что-то там считать в буфер, не смещая свой указатель, в то время как указатель файлового дескриптора, с которым работает lseek, конечно же, уедет.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
жучара
Сообщения: 950
ОС: астралинукс

Re: Как сравнить позиции счётчика байтов в открытом (fopen) бинарном файле?

Сообщение жучара »

Bizdelnick писал:
23.09.2022 18:28
А кто сказал, что можно мешать lseek c fseek? lseek — системный вызов, fseek — функция библиотеки буферизованного ввода-вывода. То есть fseek может что-то там считать в буфер, не смещая свой указатель, в то время как указатель файлового дескриптора, с которым работает lseek, конечно же, уедет.
я не понимаю, почему lseek должен куда-то уезжать. Ещё и конечно же. Он должен установить счётчик байтов куда велено и вернуть смещение и никуда не уезжать. А если уезжает- грош цена такой функции. Установил смещение, а на самом деле оно другое- и другое и возвращает. Мда.
Я просто читаю маны.
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5289
ОС: Gentoo

Re: Как сравнить позиции счётчика байтов в открытом (fopen) бинарном файле?

Сообщение /dev/random »

жучара писал(а):
23.09.2022 19:27
я не понимаю, почему lseek должен куда-то уезжать. Ещё и конечно же. Он должен установить счётчик байтов куда велено и вернуть смещение и никуда не уезжать. А если уезжает- грош цена такой функции. Установил смещение, а на самом деле оно другое- и другое и возвращает. Мда.
Функции, работающие с указателями FILE*, реализованы поверх функций, работающих с файловыми дескрипторами (int fd), но при этом полагаются на то, что напрямую файловым дескриптором вы пользоваться не будете. Например, fread() читает более крупные порции, чем вы запрашиваете, и вместо возвращения помещает лишние данные в буфер, чтобы следующий вызов fread() мог просто взять их из буфера.

Функция fseek() гарантирует, что функции, работающие с FILE*, вернут данные, расположенные в запрошенном месте, но с файловым дескриптором может сделать всё, что ей угодно (лишь бы это не помешало дальнейшему использованию этого FILE*). В данном случае, судя по всему, она решила сэкономить системный вызов, предположив, что вы после неё вызовете fread(). Она могла бы вызвать lseek() и позволить последующему fread() вызвать read(), но это было бы целых два системных вызова. Вместо этого она, судя по всему, вызвала read() и поместила результат в буфер, чтобы та позиция, на которую вы хотели переместиться, оказалась внутри буфера (а позиция файлового дескриптора сдвинулась в положение сразу после буфера). В этом случае последующий fread() не будет использовать системных вызовов, а просто вернёт данные из буфера.

Используйте либо FILE*, либо fd, но не и то, и другое.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20792
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Как сравнить позиции счётчика байтов в открытом (fopen) бинарном файле?

Сообщение Bizdelnick »

Достаточно посмотреть, что происходит, с помощью strace:

Код:

openat(AT_FDCWD, "test", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=60, ...}) = 0
lseek(3, 0, SEEK_CUR) = 0
lseek(3, 0, SEEK_CUR) = 0
fstat(1, {st_mode=S_IFCHR|0666, st_rdev=makedev(0x1, 0x3), ...}) = 0
ioctl(1, TCGETS, 0x7ffcb4ef26c0) = -1 ENOTTY (Неприменимый к данному устройству ioctl)
lseek(3, 0, SEEK_SET) = 0
read(3, "\0", 1) = 1

lseek(3, 0, SEEK_CUR) = 1
lseek(3, 0, SEEK_SET) = 0
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 60

lseek(3, 0, SEEK_CUR) = 60
write(1, "x = 0\nx = 1\nx = 60\n", 19) = 19
Выделил то, что происходит внутри функции fseek.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
жучара
Сообщения: 950
ОС: астралинукс

Re: Как сравнить позиции счётчика байтов в открытом (fopen) бинарном файле?

Сообщение жучара »

/dev/random писал:
23.09.2022 20:04
но с файловым дескриптором может сделать всё, что ей угодно (лишь бы это не помешало дальнейшему использованию этого FILE*)
а вы что имеете ввиду под файловым дескриптором? Она его не меняет, он равен 3. Вы, наверное, имеете ввиду число, которое указывает на смещение читаемого байта?

Код: Выделить всё

//m.c
#include <stdio.h>
#include <unistd.h>

int main ()
{
	FILE*  fp;
 	int df;
	
	//Вот я открыл файл
	fp = fopen ("test", "rb");
	df = fileno (fp);
	if (df == -1)
	{
		printf ("Всё плохо\n");
	}

	//Смещение от начала файла будет класть в переменную x
	int x;

	//Сместились, смещение получили, вывели
	fseek (fp, 0, SEEK_CUR);
	printf ("df = %d\n", df);
	x = lseek (df, 0, SEEK_CUR);
	printf ("x = %d\n", x);
	
	//Сместились, смещение получили, вывели
	fseek (fp, 1, SEEK_CUR);
	printf ("df = %d\n", df);
	x = lseek (df, 0, SEEK_CUR);
	printf ("x = %d\n", x);

	//Сместились, смещение получили, вывели
	fseek (fp, 0, SEEK_CUR);
	printf ("df = %d\n", df);
	x = lseek (df, 0, SEEK_CUR);
	printf ("x = %d\n", x);
	
	return 0;
	
}
Я просто читаю маны.
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5289
ОС: Gentoo

Re: Как сравнить позиции счётчика байтов в открытом (fopen) бинарном файле?

Сообщение /dev/random »

жучара писал(а):
23.09.2022 21:40
а вы что имеете ввиду под файловым дескриптором? Она его не меняет, он равен 3.
Я имел в виду состояние файлового дескриптора. В первую очередь позицию чтения/записи, но также и другие параметры, например, блокировки.
Спасибо сказали:
Ответить