Fopen в C на солярисе - PullRequest
       38

Fopen в C на солярисе

1 голос
/ 07 февраля 2009

Я пытался заставить этот код работать часами! Все, что мне нужно сделать, это открыть файл, чтобы увидеть, является ли он реальным и читаемым. Я новичок в C, так что я уверен, что есть что-то глупое, что я скучаю. Вот код (сокращенно, но скопированный):

#include <stdio.h>

main() {
    char fpath[200];
    char file = "/test/file.this";
    sprintf(fpath,"~cs4352/projects/proj0%s",file);

    FILE *fp = fopen(fpath,"r");
    if(fp==NULL) {
        printf("There is no file on the server");
        exit(1);
    }
    fclose(fp);
    //do more stuff
}

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

Редактировать 1: Я знаю, что fpath заканчивается как "~ cs4352 / projects / proj0 / test / file.this"

Редактировать 2: Я также пробовал использовать абсолютный путь к файлу. В обоих случаях я могу проверить правильность построения путей с помощью ls.

Редактировать 3: Там errno равно 2 ... В настоящее время я пытаюсь отследить, что это значит в Google.

Редактировать 4: Хорошо, errno из 2: «Нет такого файла или каталога». Я получаю это, когда ссылочный путь в fopen - "/home/courses1/cs4352/projects/proj0/index.html", который, как я подтвердил, существует, и у меня есть права на чтение. Что касается кода C, перечисленного ниже, в нем может быть несколько семантических ошибок / ошибок новичка, но gcc не дает мне никаких предупреждений во время компиляции, и код работает точно так, как должен, за исключением того, что он говорит, что он продолжает выплевывать errno из 2. Другими словами, я знаю, что все массивы strings / char работают правильно, но единственное, что может вызвать проблемы, - это вызов fopen().

Решение: Хорошо, процедура access () - это то, что мне помогло больше всего (и что я до сих пор использую, так как это меньше кода, не говоря уже о более элегантном способе сделать это). Проблема на самом деле возникла из-за того, что я не объяснил вам всем (потому что я не видел ее, пока не использовал access ()). Чтобы извлечь файл, я разбивал строки с помощью strtok () и разбивал только на «\ n», но, поскольку это система UNIX, мне нужно было также добавить «\ r» к ней. Как только я это исправил, все стало на свои места, и я уверен, что функция fopen () также будет работать, но я не проверял это.

Спасибо всем за ваши полезные советы, и особенно Полу Бекингему за то, что он нашел это замечательное решение.

Ура!

Ответы [ 7 ]

6 голосов
/ 07 февраля 2009
  1. "~" расширяется оболочкой и не раскрывается fopen.
  2. Чтобы проверить наличие и читаемость файла, рассмотрите возможность использования функции доступа POSIX.1:
#include <unistd.h>

if (access ("/path/to/file", F_OK | R_OK) == 0)
{
  // file exists and is readable
}
5 голосов
/ 07 февраля 2009

Во-первых, file необходимо объявить как char* или const char*, а не просто char, как вы написали. Но это может быть просто опечатка, компилятор должен по крайней мере дать предупреждение там.

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

2 голосов
/ 07 февраля 2009

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

#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif

#include <assert.h>
#include <limits.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

char *relfname(const char *name, char *buffer, size_t bufsiz)
{
    assert(name != 0 && buffer != 0 && bufsiz != 0);
    if (name[0] != '~')
        strncpy(buffer, name, bufsiz);
    else
    {
        const char *copy;
        struct passwd *usr = 0;
        if (name[1] == '/' || name[1] == '\0')
        {
            usr = getpwuid(getuid());
            copy = &name[1];
        }
        else
        {
            char username[PATH_MAX];
            copy = strchr(name, '/');
            if (copy == 0)
                copy = name + strlen(name);
            strncpy(username, &name[1], copy - &name[1]);
            username[copy - &name[1]] = '\0';
            usr = getpwnam(username);
        }
        if (usr == 0)
            return(0);
        snprintf(buffer, bufsiz, "%s%s", usr->pw_dir, copy);
    }
    buffer[bufsiz-1] = '\0';
    return buffer;
}

#ifdef TEST
static struct { const char *name; int result; } files[] =
{
    { "/etc/passwd", 1 },
    { "~/.profile", 1 },
    { "~root/.profile", 1 },
    { "~nonexistent/.profile", 0 },
};

#define DIM(x)  (sizeof(x)/sizeof(*(x)))

int main(void)
{
    int i;
    int fail = 0;
    for (i = 0; i < DIM(files); i++)
    {
        char buffer[PATH_MAX];
        char *name = relfname(files[i].name, buffer, sizeof(buffer));
        if (name == 0 && files[i].result != 0)
        {
            fail++;
            printf("!! FAIL !! %s\n", files[i].name);
        }
        else if (name != 0 && files[i].result == 0)
        {
            fail++;
            printf("!! FAIL !! %s --> %s (unexpectedly)\n", files[i].name, name);
        }
        else if (name == 0)
            printf("** PASS ** %s (no match)\n", files[i].name);
        else
            printf("** PASS ** %s -> %s\n", files[i].name, name);
    }
    return((fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
}

#endif
1 голос
/ 07 февраля 2009

Вы можете попробовать проверить errno для получения дополнительной информации о том, почему вы не получаете действительный FILE*.

Кстати - в unix глобальное значение errno устанавливается некоторыми библиотеками и системными вызовами, когда им нужно вернуть больше информации, чем просто "это не сработало". Только после соответствующего звонка гарантированно будет хорошо.

0 голосов
/ 07 февраля 2009

Подводя итог:

  1. Использовать char * file = / test / file.this ";
  2. Не ожидайте, что fopen () выполнит подстановку оболочки ~, потому что это не так. Используйте полный путь или относительный путь и убедитесь, что текущий каталог является apppripriate.
  3. ошибка 2 означает, что файл не найден. Не найдено из-за позиции №2 в этом списке.

Для дополнительного кредита использование sprintf (), подобного этому, для записи в буфер, размещенный в стеке, является опасной привычкой. Найдите и используйте snprintf (), как минимум.

Как уже упоминал кто-то здесь, использование access () было бы лучшим способом сделать то, что вы пытаетесь здесь.

0 голосов
/ 07 февраля 2009

Вы уверены, что не имеете в виду

~ / cs4352 / проекты / proj0% s "

для вашего домашнего каталога?

0 голосов
/ 07 февраля 2009

char file = "/test/file.this";

Вы, вероятно, хотите

char * file = "/test/file.this";

...