Как прочитать только первое значение из текстового файла - PullRequest
0 голосов
/ 16 января 2020

Вот лог c:

read first integer from the text file into IntegerOne

if end-of-file on intInput.dat
display error message “Input file exists but has no values”
end program execution

Текстовый файл может не иметь никаких значений или может иметь несколько значений. Если значения нет, то я хочу, чтобы оно отображало сообщение об ошибке, если оно имеет несколько значений, тогда я хочу только прочитать первое значение и сохранить значение в IntegerOne.

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

int main() {

    int arr[30];
    ifstream is("InputFile.txt");
    int cnt = 0;
    int x;
    while (cnt < arr[30] && is >> x)
    {
        arr[cnt++] = x;
    }
    cout << "The integers are:" << "\n";
    for (int i = 0; i < cnt; i++) {
        cout << arr[i] << ' ';
    }
    is.close();
}

Но я не совсем уверен, как читать только первое значение я должен просто изменить «arr [30]» на «arr [1]»? Я не решаюсь сделать это, потому что позже мне нужно будет прочитать только второе значение (и проверить, существует ли оно). Любые комментарии будут оценены!

Ответы [ 5 ]

3 голосов
/ 16 января 2020
  • Укажите полный путь при открытии потока:

    ifstream is( "c:/temp/test.txt" );  // the file is automatically closed on destruction
    
  • Вы должны убедиться, что файл был успешно открыт :

    if ( !is ) // did we succesfully open the file
    {
      cout << "could not open file";
      return -1;
    }
    
  • Вы можете прочитать целое число и проверить успех за один шаг:

    if ( is >> value )
      cout << "contains one value, at least";
    else
      cout << "empty file";
    
2 голосов
/ 16 января 2020

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

ifstream is("InputFile.txt"); //open file
if(!is){
   //file can't be opened for some reason (e.g. doesn't exist)
   return;
}
int first_value = -1;
if(is.peek() != EOF){
   //file isn't empty empty
   is >> first_value;
}
is.close();
2 голосов
/ 16 января 2020

Это один метод для чтения по первому значению:

int first_value;
is >> first_value;

Если вам нужно, вы можете сохранить его в массиве:
arr[0] = first_value;

Для чтения непосредственно в первое значение массива:
is >> arr[0];

1 голос
/ 16 января 2020

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

Прежде всего, избегайте использования Волхвы c -Номера или Закодированные имена файлов в вашем коде. Если вам нужна константа для объявления вашего массива, то либо #define константа, либо объявите значение const int. Чтобы открыть имя файла, main() принимает аргументы, int main (int argc, char **argv) (где arg c - это счетчик аргументов , указывающий, сколько отдельных строк символов содержится в вашем аргумент-векторе ), который позволяет вам передать имя файла для открытия в качестве первого аргумента вашей программе (или вы можете принять его как ввод для stdin). Таким образом, у вас есть одно удобное место для изменения размера вашего массива, и вам не нужно перекомпилировать вашу программу просто для чтения из другого файла.

Например, можно определить константу для вашего массива arr как:

#include <iostream>
#include <iomanip>
#include <fstream>

#define MAXI 30 /* if you need a constant, #define one, or declare const int */

int main (int argc, char **argv) {
    ...
    int arr[MAXI] = {0};        /* array of MAXI (30) integers */

или вместо использования #define, в C ++ вы можете объявить и инициализировать const int, например,

const int MAXI = 30;

С этим фоном вне пути, как прочитать первое целочисленное значение из файла в переменную с именем IntegerOne? (Я думаю, что вы намеревались использовать x в своем коде). Независимо от того, какое имя вы используете, подход один и тот же. Объявите переменную для хранения целочисленного значения, откройте ваш файл (проверьте, что он открыт для чтения), а затем прочитайте первое значение в вашей переменной (проверка того, что чтение выполнено), например,

    int IntegerOne;             /* separate variable for IntegerOne */
    ...
    std::ifstream f (argv[1]);  /* open file stream */

    if (!f.good()) { /* validate file stream state good */
        std::cerr << "error: file open failed.\n";
        return 1;
    }

    if (!(f >> IntegerOne)) {    /* read/validate 1st value */
        std::cerr << "Input file exists but has no values.\n";
        return 1;
    }

Если у вас есть достигнув этой точки в вашей программе, вы успешно прочитали первое значение из файла в IntegerOne, и вы можете просто вывести значение для подтверждения:

    std::cout << "IntegerOne: " << IntegerOne << '\n';  /* output IntegerOne */

Следующая задача - прочитать значения до размер вашего массива. Вы объявляете свой массив, используя целочисленную константу MAXI (макс. Число целых чисел), определенную выше:

    int arr[MAXI] = {0};        /* array of MAXI (30) integers */

( примечание: полезно инициализировать ваши POA (простые старые массивы) ) до нуля, чтобы предотвратить случайное чтение из элемента, для которого еще не было установлено значение в течение al oop, что вызовет неопределенное поведение )

Для защиты границ массива при проверке При каждом чтении в элементе вашего массива вы можете просто использовать определенную вами константу вместе со счетчиком, чтобы предотвратить запись большего числа целых чисел, чем у вас есть место для вашего массива. Вы проверяете каждое чтение так же, как и с IntegerOne выше. Соединяя оба условия, вы можете выполнить:

    int cnt = 0,                /* counter for array values */
    ...
    /* read remaining integers into arr up to MAXI values */
    while (cnt < MAXI && f >> arr[cnt])
        cnt++;

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

Если положить его в целом, вы можете сделать:

#include <iostream>
#include <iomanip>
#include <fstream>

#define MAXI 30 /* if you need a constant, #define one, or declare const int */

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

    if (argc < 2) { /* validate at least 1 argument for filename */
        std::cerr << "usage: " << argv[0] << " filename\n";
        return 1;
    }

    int IntegerOne,             /* separate variable for IntegerOne */
        cnt = 0,                /* counter for array values */
        arr[MAXI] = {0};        /* array of MAXI (30) integers */
    std::ifstream f (argv[1]);  /* open file stream */

    if (!f.good()) { /* validate file stream state good */
        std::cerr << "error: file open failed.\n";
        return 1;
    }

    if (!(f >> IntegerOne)) {    /* read/validate 1st value */
        std::cerr << "Input file exists but has no values.\n";
        return 1;
    }
    std::cout << "IntegerOne: " << IntegerOne << '\n';  /* output IntegerOne */

    /* read remaining integers into arr up to MAXI values */
    while (cnt < MAXI && f >> arr[cnt])
        cnt++;

    /* output array, 10 values per line */
    for (int i = 0; i < cnt; i++) {
        if (i && i % 10 == 0)
            std::cout << '\n';
        std::cout << std::setw(5) << arr[i];
    }
    if (cnt)  /* conditionally output final newline if array values printed */
        std::cout << '\n';
}

Всякий раз, когда вы пишете код, который должен удовлетворять нескольким условиям, go тестируйте эти условия для проверки правильности работы вашего кода.

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

Не существует файл:

$ ./bin/read1stvalue+array goldfish
error: file open failed.

Пустой файл:

$ ./bin/read1stvalue+array dat/empty.txt
Input file exists but has no values.

Файл с однозначным значением 321:

$ ./bin/read1stvalue+array dat/oneint.txt
IntegerOne: 321

Файл с 10 целочисленными значениями после 1-го значения в файле, например,

$ cat dat/int_cnt+10_by-5.txt
10
  702  344  138   77  294
   27   67  978  727  301

Чтение вышеуказанного файла, вывод значений массива 10 на строку:

$ ./bin/read1stvalue+array dat/int_cnt+10_by-5.txt
IntegerOne: 10
  702  344  138   77  294   27   67  978  727  301

Файл с 30 целочисленными значениями после 1-го значения в файле, например,

$ cat dat/int_cnt+30_by-5.txt
30
  393  936   97  365  928
  257  645  987  221   22
  237  853  584  905  819
  910  576  730  859  495
   13  818  281  908  582
  421  156  177  831  646

Чтение вышеуказанного файла, вывод значений массива 10 на строку:

$ ./bin/read1stvalue+array dat/int_cnt+30_by-5.txt
IntegerOne: 30
  393  936   97  365  928  257  645  987  221   22
  237  853  584  905  819  910  576  730  859  495
   13  818  281  908  582  421  156  177  831  646

Файл с 50 целочисленными значениями после 1-го значения в файле, например,

$ cat dat/int_cnt+50_by-5.txt
50
  302  697  190  743  391
  709  699  824  839  976
  817  246  695  833  918
    2  712  422  737  326
  706  170  394  720  903
  798  291  683  682  971
   70  216  668  260  960
   59  969  891  883   40
  867  700  519  795  766
  437   29  710   91  767

Чтение выше файла , вывод значений массива 10 на строку:

$ ./bin/read1stvalue+array dat/int_cnt+50_by-5.txt
IntegerOne: 50
  302  697  190  743  391  709  699  824  839  976
  817  246  695  833  918    2  712  422  737  326
  706  170  394  720  903  798  291  683  682  971

( note в массиве сохраняются только первые 30 значений)


Использовать контейнеры STL вместо простых старых массивов

Пока нет ничего плохого в том, чтобы знать, как обращаться с простыми старыми массивами - их использование на десятилетия унаследовано от C ++, новый код должен использовать контейнеры, предоставляемые стандартной библиотекой шаблонов, которые обеспечивают автоматическое управление памятью c, возможность чтобы добавить дополнительные элементы, если необходимо, et c .. std::vector можно использовать для замены любого старого старого массива. Найдите минутку, чтобы посмотреть, как она используется, и примеры, предоставленные для каждой функции-члена по адресу std :: vector . (они действительно делают жизнь намного проще)

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

1 голос
/ 16 января 2020

Ответ для использования C ++ 17 или Boost

  1. используйте std :: filesystem для управления путями

  2. проверьте, существует ли файл и размер файла> 0 (std :: filesystem :: существующие (путь) и std :: filesystem :: file_size (путь))

  3. если все в порядке - прочитайте файл (используйте fstream )

см. Код:

#include <iostream>
#include <filesystem>
#include <fstream>


int main() {

    auto path{std::filesystem::current_path() / "data"};

    if (!std::filesystem::exists(path)) {
       return -1;
    } else {
        std::cout << "File exists!" << std::endl;
    }

    uint64_t file_size{std::filesystem::file_size(path)};
    if (!file_size) {
        return -2;
    } else {
        std::cout << "File size : " << file_size << std::endl;
    }

    std::fstream in_stream{path, std::ios::in};

    char ch;
    in_stream.read(&ch, 1);

    std::cout << "first byte is : " << ch << std::endl;

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...