Низкоуровневый стандарт C для приема имени файла и печати содержимого файла на стандартный вывод

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

Проблемы:

  1. printf("введите имя файла"); заявление никогда не появляется
  2. он никогда не открывает файл; вместо этого все, что вводится пользователем, выводится на экран, а затем выводится сообщение об ошибке "нет такого файла или каталога", и программа завершает работу.
  3. после того, как программа существует, я вижу "введите имя файла", напечатанное перед подсказкой в ​​терминале

КОД:

    {
        printf("Enter the filename: ");
        read(STDIN_FILENO, userInput, sizeof(userInput));
        if((input_file1 = open(userInput, O_RDONLY)) < 0)
        {
            perror(userInput);
            exit(1);
        }

        while((n = read(input_file1, buffer, sizeof(buffer))) > 0)
        {
            if((write(STDOUT_FILENO, buffer, n)) < 0)
            {
                perror("failed to write to standard-out");
                close(input_file1);
                exit(1);
            }
        }
    }

Приставка:

machine{user1}168: ls // to show that the file exists
a.out  backup  file1 
machine{user1}170: ./a.out
file1 // this is user input
file1 // this is printed for no reason
: No such file or directory // ????
Enter the filename: machine{user1}171: // now the prompt is printed...? 

2 ответа

Решение

<stdio.h> подпрограммы ввода / вывода буферизуются (см. stdio(3) и setbuf (3). Вам нужно вызвать fflush (3) (в недавней libc она вызывается неявно для stdout если вы читаете с fgets или же scanf). И вам действительно следует избегать смешивания файловых дескрипторов и FILE обрабатывает один и тот же вывод или ввод (смотрите fileno(3), но всегда вызывайте fflush....). Так замени

         printf("Enter the filename: ");
         read(STDIN_FILENO, userInput, sizeof(userInput));

с

         printf("Enter the filename: \n");
         fflush(NULL);
         if (!fgets(userInput,sizeof(userInput),stdin))
           { perror("fgets"); exit(EXIT_FAILURE); };

На самом деле здесь fflush можно было бы избежать, если вы держите очень важный завершающий \n (новая линия). Если вы не хотите новой строки, вам лучше позвонить fflush (но некоторые libc называют это для вас).

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

Но вы должны узнать о getline (3) (чтобы избежать линий фиксированной длины). В системах Linux и GNU стоит использовать readline: он позволяет вам давать сексуальные подсказки, а вашему пользователю редактировать набранные строки.

Ваше приглашение никогда не появляется, потому что вы используете read() вместо одной из стандартных функций ввода / вывода (scanf(), fgets()и т. д.), чтобы получить вход. Либо измените функцию ввода, либо используйте fflush(stdout) или же fflush(0) перед звонком read(),

Ваше чтение включает новую строку, поэтому при открытии пытается открыть файл с новой строкой в ​​конце имени. Этот файл не существует, поэтому открыть не удается.

{
    printf("Enter the filename: ");
    if (fgets(userInput, sizeof(userInput), stdin) == 0)
    {
        fprintf(stderr, "Oops!\n");
        exit(1);
    }
    userInput[strlen(userInput)-1] = '\0';
    if ((input_file1 = open(userInput, O_RDONLY)) < 0)
    {
        perror(userInput);
        exit(1);
    }

    while ((n = read(input_file1, buffer, sizeof(buffer))) > 0)
    {
        if (printf("%.*s", n, buffer)) != n)
        {
            perror("failed to write to standard-out");
            close(input_file1);
            exit(1);
        }
    }
    close(input_file1);
}
Другие вопросы по тегам