Попытка поиска в файле произвольного доступа с использованием строки

#c #file #search #io

#c #файл #Поиск #io

Вопрос:

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

Ранее я искал файл произвольного доступа, используя метод

  FILE fpnt = fopen(FILE_NAME, "rb ");

 User tempUser = {"", "", 0, "", 0};
 printf("Enter the id number of the user to findn");
 scanf("%d", idNum);
 fseek(fpnt, (idNum - )* sizeof(User), SEEK_SET);
 fread(amp;tempUser, sizeof(User), 1, fpnt) != EOF amp;amp; found == 0;
  

Я не понимаю, как это всегда находит правильного пользователя, когда смещение не всегда обязательно совпадает с идентификатором, который я бы предположил. Но проблема заключается в том, что я пытаюсь получить доступ к файлам, используя данные, отличные от целых чисел.

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

  typedef enum tUserLevel {
     MANAGER = 1,
     CLERK = 0,
     NOTFOUND = 9001
 }level;


 typedef struct tUser {
     char userName[20];
     char password[20];
     level priviledgeLevel;
 }User;

do {
    fseek(fpnt, offSet * sizeof(User), SEEK_SET);
    if (fread(amp;tempUser, sizeof(User), 1, fpnt) == EOF)
        endOfFile = EOF;        
    rewind(fpnt);
    offSet  ;
} while (endOfFile!=EOF amp;amp; !strcmp(username, tempUser.userName));

if (endOfFile==EOFamp;amp; strcmp(username, tempUser.userName)) {
    printf("The User was not foundn");
    return noUser;

    //return noUser;
}
  

Итак, что должно произойти, так это то, что файл проверит каждого пользователя на наличие введенного имени пользователя (это переменная с именем username) и сравнит два и остановится, если оба верны. Я не уверен, как это происходит на самом деле, или смещение влияет на указатель в файле так, как я хочу. Что действительно происходит, так это то, что я всегда получаю EOF, так что эта часть кода всегда выполняется даже после одного чтения. У меня было 4 тестовых пользователя, есть ли лучший способ поиска этих файлов по строке, чтобы я мог прочитать их и отредактировать в файле, или это лучший способ, и я где-то что-то путаю?

Комментарии:

1. fseek и rewind здесь нет смысла. Код возвращается к началу файла (rewind), а затем немедленно разворачивается и возвращается к тому же, что было минуту назад (fseek). Два вызова могут быть просто удалены.

2. Когда fread() вернется EOF?

3. Zing, смещение инициализируется нулевым значением yes, поэтому оно начинается с начала и увеличивается. Я не уверен, что местоположение указателя должно было оставаться на тех же позициях между итерациями, поэтому я смещаю его вручную.

Ответ №1:

В вашем первом примере предполагается, что файл состоит из User записей фиксированной длины, упорядоченных по идентификационному номеру, без пробелов. Запись для идентификатора 1 будет иметь смещение 0, а запись для идентификатора N будет иметь значение (N - 1) * sizeof(User) . Если это то, что на самом деле содержит файл, это разумное предположение.

Код в нижней части вашего вопроса, похоже, страдает от кризиса идентификации. Он не может определить, являются ли записи последовательными и упорядочены по идентификатору, или файл должен быть найден путем сопоставления на username . Это неработоспособный гибрид двух разных методов поиска. Вам нужно выбрать один метод и использовать его.

Если файл упорядочен по идентификатору и не содержит пробелов (а вы ищете по идентификатору), вам не нужно выполнять поиск в while цикле.

С другой стороны, если файл либо неупорядочен, либо содержит пробелы, тогда необходимо выполнить поиск. В этом случае вызовы fseek и rewind не нужны. Просто начните с начала файла и читайте каждую запись последовательно, по одной за раз, пока не найдете ту, которая соответствует запрошенному имени пользователя.

Кроме того, сравнение возвращаемого значения fread с EOF является неправильным. fread Функция возвращает количество фактически прочитанных элементов. Если возвращаемое число не равно количеству элементов, которые вы указали в вызове, то либо произошла ошибка чтения, либо вы попали в конец файла. EOF Константа предназначена для использования с подобными функциями, fgetc которые возвращают символьные значения.

Комментарии:

1. Значит, если я повторно вызову fread(), он переместит указатель по файлу, как это сделала бы fscanf ()?

2. Спасибо. Теперь я понимаю это. Я должен читать его последовательно и сравнивать каждое прочитанное с введенными данными. Что касается того, что вы упомянули с пробелами, чтобы гарантировать, что я не оставляю пробелов, я должен предположить, что я могу просто читать последовательно, пока не будет найдена пустая структура или «удаленная структура», и перезаписать это. И чтобы фактически отредактировать данные, мне придется сместить указатель отрицательно на размер структур, которые я пишу. Спасибо за объяснение.

3. @Deeswoc Под «пробелами» я имел в виду пробелы в последовательности значений идентификатора внутри файла. Не пробелы в данных, где нет, например, ничего, кроме нулей или чего-то подобного. Смысл был в том, что если вы ищете по идентификатору и вычисляете смещение для этого идентификатора в файле, то вы предполагаете, что каждый идентификатор в последовательности до этой точки существует в файле. Например, если вы ищете идентификатор 5, но ваш файл содержит записи только для идентификаторов 1,2 и 5, то как вы вычисляете правильное смещение? Конечно, не с помощью (id - 1) * sizeof(User) .

4. @Deeswoc И, конечно, это означает, что повторяющиеся идентификаторы также не могут существовать, например, файл с записями для идентификаторов 1,1,2,3,4,4,5. В этом случае (id - 1) * sizeof(User) также выдает неверное смещение, даже если пробелов нет.