2009-02-07 1 views
1

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

#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 
} 

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

Edit 1: Я знаю, что FPATH заканчивается как "~ cs4352/проекты/proj0/тест/file.this"

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

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

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

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

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

Cheers!

+0

Я действительно считаю, что «~ cs4352» на самом деле не понят ОС. замените его реальным путем. ~ cs4352 просто заменяется оболочкой. но здесь нет оболочки. но, как вы говорите, вы тоже пробовали абсолютные пути. Я думаю, это еще одна проблема. –

+0

Системная ошибка.h должна иметь список errno. В MacOS X 2 нет «такого файла или каталога». Мне нравится ответ Джо и Шт. – dmckee

+0

просто используйте perror, он показывает ошибку в удобочитаемой форме, или strerror для перевода errno –

ответ

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

if (access ("/path/to/file", F_OK | R_OK) == 0) 
{ 
    // file exists and is readable 
} 
+0

Большое спасибо за то, что вы дали мне решение POSIX !!! Это сработало красиво. Отличный день! – Mike

0

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

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

символ * файл = "/test/file.this";

0

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

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

для вашей домашней директории?

1

Вы можете попробовать изучения errno для получения дополнительной информации о том, почему ты» re not get a valid FILE*.

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

5

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

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

0

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

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

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

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

2

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

#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 
+0

приятный +1 за усилие (не проверял этот код, но он выглядит ясным: p). сегодня я слышал о функции «wordexp» posix, которая делает это и многое другое (другие расширения). может быть, вы еще этого не знаете и можете найти его полезным :) –

+0

Я слабо помню, что он существует; Я никогда не использовал его - или функцию fnmatch(). Они из того, что было POSIX.2, и, как правило, забываются. –

+0

И, FWIW, этот код использует определение домашнего каталога из/etc/passwd (или базы данных паролей); wordexp() использует текущее значение $ HOME (которое обычно, но не обязательно, одно и то же). Разумеется, изменение является тривиальным. –