#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)
также выдает неверное смещение, даже если пробелов нет.