Как реализовать команду Unix ls -s в C? - PullRequest
2 голосов
/ 06 июня 2010

Мне нужно написать программу на C, которая возвращает размер файла в блоках, как команда ls -s. Пожалуйста, помогите.

Я пытался использовать функцию stat () (st_blksize) ... И я не могу ее реализовать.

Мой код выглядит так

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>

void main(int argc, char **argv)
{
    DIR           *dp;
    struct dirent *dirp;
    struct stat    buf;

    if(argc < 2)
    {
        dp = opendir(".");
    }

    if(dp == NULL)
    {
        perror("Cannot open directory ");
        exit(2);
    }

    while ((dirp = readdir(dp)) != NULL)
    {
        printf("%s\n", dirp->d_name);
        if (stat(".", &buf))
        printf("%d ", buf.st_blksize);
    }

    closedir(dp);
    exit(0);
}

Это дает ошибку, размер буфера не объявлен. Не знаю в чем проблема.

Добавление

Спасибо за исправление. Я включил заголовочный файл <sys/stat.h>. Теперь он дает предупреждение:

warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘__blksize_t’

Я новичок в C, поэтому не могу понять, какое должно быть возможное решение.

Ответы [ 5 ]

5 голосов
/ 06 июня 2010

Вы должны включить правильный заголовок:

#incude <sys/stat.h>

Это объявляет структуру и связанные функции.

Обратите внимание, что stat() возвращает ноль в случае успеха, поэтому ваш тест нуждается в изменении (и, как указал @jsmchmier в комментарии, при вызове stat следует использовать dirp->d_name вместо строкового литерала "."). Кроме того, st_blksize - это размер блоков диска, а не размер файла, то есть st_size (измеряется в байтах).

POSIX говорит:

off_t st_size Для обычных файлов размер файла в байтах. Для символических ссылок длина в байтах путь содержится в символической ссылке.

blksize_t st_blksize Предпочтительный размер блока ввода-вывода для конкретной файловой системы для этого объекта. В некоторых типах файловых систем это может варьироваться от файла к файлу.

blkcnt_t st_blocks Количество блоков, выделенных для этого объекта.

Обратите внимание, что старые (очень старые) версии Unix не поддерживали st_blksize или st_blocks. Я ожидаю, что большинство текущих версий делают.


Теперь он выдает предупреждение ... предупреждение: формат "% d" ожидает тип "int", но аргумент 2 имеет тип "__blksize_t"

Скорее всего, __blksize_t является целым типом без целочисленного значения, похожим на size_t. Я бы, наверное, использовал простое приведение:

printf("Block size = %d\n", (int)buf.st_blksize);

В качестве альтернативы, если у вас есть C99, вы можете использовать средства с <inttypes.h>, чтобы использовать больший размер:

printf("Block size = %" PRIu64 "\n", (uint64_t)buf.st_blksize);

На практике это излишне; размер блока вряд ли превысит 2 ГБ в этом десятилетии, поэтому int, вероятно, будет достаточно в обозримом будущем.

1 голос
/ 07 июня 2010

Осторожно, одна ошибка в вашем коде заключается в том, что dp указывает на мусор и инициализируется, только если argc меньше 2, но вы все еще пытаетесь использовать его в цикле while и также пытаетесь 1004 * это. Если вы вызовете приложение с какими-либо аргументами, оно, вероятно, завершится сбоем.

1 голос
/ 06 июня 2010

С man 2 stat на моем Mac OS X box:

NAME
     fstat, fstat64, lstat, lstat64, stat, stat64 -- get file status  

SYNOPSIS  
     #include <sys/stat.h>  

     int
     fstat(int fildes, struct stat *buf);

Обратите внимание на #include <sys/stat.h>, который вы еще не сделали.Без сомнения, здесь определено фактическое расположение struct stat, на что жалуется ваш компилятор.

Это один аспект справочных страниц, который не всегда обсуждается с новичками, но очень действительно полезно: весь API Unix документирован в них.О, не всегда легче всего найти функцию, когда вы знаете, что она должна делать, но не знаете, как она называется, но all ответы есть.

1 голос
/ 06 июня 2010

Откройте файл и введите stat / fstat. Поле структуры st_blocks должно содержать информацию, которую вы хотите. Если вы имеете дело с каталогом, используйте opendir, readdir, closedir (posix) ... Просто указатели, чтобы начать работу.

EDIT

Добавьте unistd.h и sys / stat.h. Затем запомните, что stat возвращает 0 в случае успеха, поэтому

if (stat(dirp->d_name, &buf) == 0)

и я изменил "." к названию "элемента", который вы хотели, я полагаю. Другое изменение заключается в использовании st_blocks, а не st_blksize, который говорит, насколько велик каждый блок (например, 1024 или 4096 или ...), а -s возвращает размер в количестве блоков, а не размер блока.

Фрагмент кода, конечно, неполон: если вы передаете аргумент, dp не инициализируется и даже dp == NULL может потерпеть неудачу, вы должны были его аннулировать раньше:

    DIR           *dp = NULL;
    struct dirent *dirp = NULL;
0 голосов
/ 20 февраля 2013

Чтобы избежать предупреждения, измените% d на% ld в строке: printf ("% d", buf.st_blksize);

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