Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
lseek — изменение позиции в файле
lseek() — это системный вызов в Unix/Linux, который изменяет текущую позицию (offset) в открытом файле. Это позволяет перемещаться по файлу произвольным образом при последовательном чтении/записи.
Сигнатура функции
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
Параметры:
fd— файловый дескриптор (файл, открытый черезopen())offset— смещение в байтах относительноwhencewhence— точка отсчёта смещения
Возвращаемое значение:
- Новая позиция в файле (в байтах от начала)
-1при ошибке (и устанавливаетсяerrno)
Параметры whence
whence определяет, от какой точки считать смещение:
SEEK_SET // 0 — от начала файла
SEEK_CUR // 1 — от текущей позиции
SEEK_END // 2 — от конца файла
Примеры использования
1. Перейти в начало файла:
#include <unistd.h>
#include <fcntl.h>
#include <iostream>
int main() {
int fd = open("file.txt", O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
// Переместить указатель в начало
off_t pos = lseek(fd, 0, SEEK_SET);
std::cout << "Current position: " << pos << std::endl; // 0
close(fd);
return 0;
}
2. Переместить указатель в конец файла:
int fd = open("file.txt", O_WRONLY);
// Переместиться в конец файла
lseek(fd, 0, SEEK_END);
// Теперь write() добавит данные в конец
write(fd, "new data\n", 9);
close(fd);
3. Получить размер файла:
int fd = open("file.txt", O_RDONLY);
// Переместиться в конец и получить текущую позицию
off_t size = lseek(fd, 0, SEEK_END);
std::cout << "File size: " << size << " bytes" << std::endl;
close(fd);
4. Переместиться на N байт вперёд:
int fd = open("file.txt", O_RDONLY);
// Читаем первые 100 байт
char buffer[100];
read(fd, buffer, 100);
// Перемещаемся на 50 байт назад
lseek(fd, -50, SEEK_CUR);
// Теперь читаем ещё 50 байт (с перекрытием)
read(fd, buffer, 50);
close(fd);
Практический пример: случайный доступ к файлу
#include <unistd.h>
#include <fcntl.h>
#include <iostream>
#include <cstring>
struct Record {
int id;
char name[50];
float salary;
};
int main() {
int fd = open("records.bin", O_RDONLY);
// Читаем 5-й запись (offset = 4 * sizeof(Record))
int record_num = 4; // 0-based index
off_t offset = record_num * sizeof(Record);
if (lseek(fd, offset, SEEK_SET) == -1) {
perror("lseek");
return 1;
}
Record rec;
if (read(fd, &rec, sizeof(Record)) != sizeof(Record)) {
perror("read");
return 1;
}
std::cout << "Record: " << rec.id << " " << rec.name << std::endl;
close(fd);
return 0;
}
Важные особенности
1. Offset может быть больше размера файла:
int fd = open("file.txt", O_WRONLY);
lseek(fd, 1000000, SEEK_SET);
write(fd, "data", 4); // Создаст "дыру" в файле
close(fd);
Этот файл будет занимать 1000004 байта, но на диске физически храниться будут только последние 4 байта. Остальное — разреженное пространство (sparse file).
2. Позиция отслеживается в процессе дескриптора:
int fd = open("file.txt", O_RDONLY);
read(fd, buf1, 10); // читаем 10 байт, pos = 10
lseek(fd, 0, SEEK_SET); // сбрасываем в начало
read(fd, buf2, 10); // читаем ещё 10 байт (те же самые)
Каждый дескриптор имеет свою позицию. Если открыть один и тот же файл дважды, позиции будут независимы.
3. Ошибки при lseek:
off_t new_pos = lseek(fd, 100, SEEK_SET);
if (new_pos == -1) {
if (errno == EINVAL) {
std::cout << "Invalid file descriptor or whence value" << std::endl;
} else if (errno == EOVERFLOW) {
std::cout << "Offset value is too large" << std::endl;
}
}
Применение в реальных проектах
1. Логирование — добавление данных в конец лога
void append_to_log(const char* filename, const char* message) {
int fd = open(filename, O_WRONLY | O_APPEND);
lseek(fd, 0, SEEK_END);
write(fd, message, strlen(message));
close(fd);
}
2. Работа с бинарными файлами — случайный доступ к записям БД
// Читаем запись N из структурированного бинарного файла
void read_record(int record_num, Record& rec) {
int fd = open("database.bin", O_RDONLY);
lseek(fd, record_num * sizeof(Record), SEEK_SET);
read(fd, &rec, sizeof(Record));
close(fd);
}
3. Работа с памятью — отладка
// Получаем размер файла
off_t file_size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET); // Возвращаемся в начало
Альтернативы
fseek() — версия для потоков (FILE*):
FILE* file = fopen("file.txt", "rb");
fseek(file, 100, SEEK_SET);
fclose(file);
mmap() — отображение файла в память для быстрого доступа:
int fd = open("file.txt", O_RDONLY);
char* data = (char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
// Теперь обращаемся к файлу как к массиву
data[100] // доступ к 100-му байту
munmap(data, size);
close(fd);
Итог
lseek() — это фундаментальная функция для работы с файлами, позволяющая:
- Получать размер файла
- Осуществлять случайный доступ
- Перемещаться по файлу произвольным образом
- Добавлять данные в конец файла
Это критически важно для системного программирования на C/C++ и работы с файловой системой.