Как прочитать плоский файл и поместить данные в соответствующую переменную - PullRequest
1 голос
/ 21 октября 2019

У меня есть плоский файл (txt файл), содержащий некоторое поле:

Первичный ключ, Имя, Адрес, Зарплата, разделенные |как:

A0001|John|New York City|12000
A0002|Daisy|New Delhi|32000
A0003|Dany|London|23000

.. и т. д.

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

Я хочу получить следующий результат:

Input the primary key: A0002

Result:
Name = Daisy
Address = New Delhi
Salary = 32000

Input the primary key: 

Ответы [ 2 ]

1 голос
/ 21 октября 2019

Давайте начнем с очень простого подхода, который использует плоский файл для вашего хранилища и при каждом запросе циклически перебирает плоский файл, пытаясь сопоставить ваш key с первым полем. Если совпадение найдено, просто используйте sscanf для разделения значений (игнорируя 1-е поле, используя модификатор подавления назначения для вашего sscanf спецификатора преобразования для этого поля, например, '*'). Распечатайте значения. Если ключ не найден в файле, скажем так.

Используя fgets() для ввода, вы можете просто принимать ввод, пока пользователь не нажмет Enter на пустой строке дляключ. (вы просто проверяете, является ли 1-ый символ '\n' и, если это так, прерываете цикл).

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

Собрав все вместе, вы можете сначала открыть и проверить ваш файл открыт для чтения.

#include <stdio.h>
#include <string.h>

#define MAXN   64   /* if you need a constand, #define one (or more) */
#define MAXC 1024   /* (don't skimp on buffer size) */

int main (int argc, char **argv) {

    /* use filename provided as 1st argument ("flatfile.txt" by default) */
    FILE *fp = fopen (argc > 1 ? argv[1] : "flatfile.txt", "r");

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

Теперь начните свой непрерывный цикл, который будет читать key от пользователя, обрезать '\n' с конца клавиши (вы не хотите это как часть сравнения),и получите длину ключа:

    for (;;) {  /* loop continually until [Enter] on empty line */
        char buf[MAXC], name[MAXN], city[MAXN], key[MAXN];
        unsigned salary, len, found = 0;

        rewind (fp);    /* rewind file to beginning */
        fputs ("\nInput the primary key: ", stdout);    /* prompt for key */
        if (!fgets (key, MAXN, stdin) || *key == '\n')  /* read key */
            break;
        key[strcspn (key, "\n")] = 0;                   /* trim '\n' */
        len = strlen(key);                              /* get key length */

Получив эту информацию, переберите файл, читая каждую строку в буфер buf, а затем используйте strcmp для сравнения первых символов len сваш key, и если есть совпадение, распечатайте его и установите флаг found и прервите цикл чтения файла. В конце, если found не установлен, сообщите пользователю, что ключ не найден, теперь делайте это снова, пока пользователь не нажмет Ввод в одиночку в строке, запрашивая первичный ключ:

        while (fgets (buf, MAXC, fp)) {                 /* read each line */
            if (strncmp (buf, key, len) == 0) {         /* compare key */
                /* parse line into separate values, ignoring 1st key field */
                if (sscanf (buf, "%*63[^|]|%63[^|]|%63[^|]|%u",
                                name, city, &salary) == 3) {
                    printf ("\nResult:\nName = %s\nAddress = %s\n"
                            "Salary = %u\n", name, city, salary);
                    found = 1;  /* set flag indicating key found */
                    break;      /* no sense in reading rest */
                }
            }
        }
        if (!found) /* if key not found, so indicate */
            fputs ("\nResult: (not found)\n", stdout);
    }

Осталось только закрыть входной файл. Полный пример:

#include <stdio.h>
#include <string.h>

#define MAXN   64   /* if you need a constand, #define one (or more) */
#define MAXC 1024   /* (don't skimp on buffer size) */

int main (int argc, char **argv) {

    /* use filename provided as 1st argument ("flatfile.txt" by default) */
    FILE *fp = fopen (argc > 1 ? argv[1] : "flatfile.txt", "r");

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    for (;;) {  /* loop continually until [Enter] on empty line */
        char buf[MAXC], name[MAXN], city[MAXN], key[MAXN];
        unsigned salary, len, found = 0;

        rewind (fp);    /* rewind file to beginning */
        fputs ("\nInput the primary key: ", stdout);    /* prompt for key */
        if (!fgets (key, MAXN, stdin) || *key == '\n')  /* read key */
            break;
        key[strcspn (key, "\n")] = 0;                   /* trim '\n' */
        len = strlen(key);                              /* get key length */

        while (fgets (buf, MAXC, fp)) {                 /* read each line */
            if (strncmp (buf, key, len) == 0) {         /* compare key */
                /* parse line into separate values, ignoring 1st key field */
                if (sscanf (buf, "%*63[^|]|%63[^|]|%63[^|]|%u",
                                name, city, &salary) == 3) {
                    printf ("\nResult:\nName = %s\nAddress = %s\n"
                            "Salary = %u\n", name, city, salary);
                    found = 1;  /* set flag indicating key found */
                    break;      /* no sense in reading rest */
                }
            }
        }
        if (!found) /* if key not found, so indicate */
            fputs ("\nResult: (not found)\n", stdout);
    }
    fclose (fp);   /* close file */
}

Пример входного файла

$ cat dat/flatfile.txt
A0001|John|New York City|12000
A0002|Daisy|New Delhi|32000
A0003|Dany|London|23000

Пример использования / Вывод

$ ./bin/readflatfile dat/flatfile.txt

Input the primary key: A0002

Result:
Name = Daisy
Address = New Delhi
Salary = 32000

Input the primary key: A0003

Result:
Name = Dany
Address = London
Salary = 23000

Input the primary key: A0004

Result: (not found)

Input the primary key:

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

0 голосов
/ 21 октября 2019

Поскольку вы будете выполнять поиск в данных несколько раз, чтобы сохранить данные в памяти более эффективным (для поиска) способом.

Кроме того, вам необходимо найти какие-либо проблемы с данными иразбираться с ними приемлемым образом (генерировать сообщения об ошибках / предупреждениях, либо пропускать ошибочные строки и / или отказываться от использования файла, если он поврежден).

В общем;Вы хотите:

a) способ получить необработанные данные (например, в байтах) в память. Это может быть повреждено (например, fgets(), который поврежден и непригоден для использования, потому что это зависит от кодировки по умолчанию «конца строки», которая может быть неправильной);или может быть циклом, который выполняет read() для загрузки всего файла в буфер, или (в идеале) может быть mmap().

b1) способом определения ожидаемого набора символов и кодировки (например, EBDIC, ASCII, UTF-8, UTF-16LE, ...). Это может быть так же просто, как сказать (например) «файл должен быть UTF-8», и так же сложно, как поддерживать множество различных наборов символов и кодировок с некоторой схемой для автоматического определения того, какой файл используется (например, <meta charset="UTF-8"> в HTML).

b2) способ определить, что такое «конец строки» (например, если это "\n" или "\r\n" или "\r", которые являются «стандартными» для различных операционных систем). Для этого возможно обрабатывать это автоматически надежным способом;трактуя либо '\n', либо '\r' как "конец строки", но затем игнорируя следующий символ, если он противоположен (например, если вы видите '\n', тогда это конец строки и если следующий символ '\r'он будет проигнорирован, и если вы увидите '\r', то это конец строки, а если следующий символ - '\n', он будет проигнорирован). Также обратите внимание, что «конец файла» может (должен) рассматриваться как «конец последней строки в файле», возможно, с предупреждением «конец строки не найден в конце файла».

b3) aцикл, который преобразует необработанные байты в стандартную для вашей программы кодировку и набор символов, по одному символу за раз, обнаруживая и обрабатывая вещи, которые недопустимы для любой кодировки и набора символов, используемого файла, до "конца строки"(или достигается «конец файла»; затем вызывается функция «обработать эту строку», затем увеличивается переменная «line_number» (которая будет использоваться для сообщений об ошибках - например, чтобы вы могли отобразить сообщение об ошибке, например «Неверная последовательностьбайты для UTF-8, найденные в строке 33 ", облегчают людям поиск / устранение проблемы в текстовом файле.

c) функцию" обработать эту строку ", которая:

  • разбивает исходную строку на 4 подстроки (по символам '|') и отбрасывает начальные и конечные пробелы из каждой из 4 подстрок и может преобразовывать несколько битоввставьте символы в один пробел (например, "A0001 | John |\t New York City |12000" становится "A0001", "John", "New York City" и "12000"). Это также должно обрабатывать ошибки - например, если для правильной строки недостаточно символов '|'. Эта функция также может игнорировать пустые строки и строки, которые содержат только пробелы;а также может молча игнорировать все после специального символа (например, чтобы вы могли поддерживать комментарии, например "A0001|John|New York City|12000 # This dude owes me money!").

  • набор функций для анализа и проверки каждой из строк в соответствии ск их фактическим требованиям. Например, возможно, первичный ключ должен начинаться с заглавной буквы (поэтому вам нужна функция, которая генерирует ошибки «Первичный ключ недействителен (не начинается с заглавной буквы)», а часть «имя» должна быть меньше 128символы, а число в конце ("12000") должно находиться в определенном диапазоне (и может включать / не включать запятые, поэтому "12,000" принимается или имеет другие правила, где каждое из правил нуждается в собственном хорошем описательном описании). сообщение об ошибке). Обратите внимание, что последняя функция (для обработки числа), вероятно, вернет целое число некоторого вида.

  • код для выделения памяти для структуры (буквально struct my_thing { ....}), и поместите«проверено и проанализировано» данные в структуре;затем вызовите функцию «добавить эту структуру».

d1) Какой-то способ организации структур, который эффективен для поиска (который является вашим наиболее распространенным / наиболее важным / единственным вариантом использования). Для этого я бы, вероятно, использовал хеш-таблицу (используя первичный ключ для генерации хеш-кода для использования в качестве индекса в таблице связанных списков).

d2) функция «добавить эту структуру», которая добавляетновая структура в хеш-таблице (или что вы решили использовать для организации структур).

e) функция «найти этот первичный ключ», которая использует код, который вы уже использовали для проверки и анализапользовательский ввод, а затем использует код, который вам уже нужен, чтобы вычислить хэш для первичного ключа «проверено и проанализировано»;затем использует хеш (и первичный ключ «проверено и проанализировано»), чтобы найти правильную структуру.

...