简体   繁体   中英

Sorting files based on their filetype

The program below is used to categorise files based on their filetypes, more precisely their extension. Command used for example ./sorting -f file1.jpg file2.txt file3.c then it would create jpg , txt , and c folders and put the files inside.

Here is the code

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>

void *check(char *argv[]);
void *mkdir(char *argv[]);
void *mvdr(char *argv[]);
pid_t child;

int main(int argc, char *argv[]) {
    pthread_t files[argc];  // inisialisasi awal
    int iret[argc];

    // 1. how many threads you need, setiap file
    //      -- setiap file setiap argc & argv

    // create thread every files
    if (argc == 1)
        return 0;

    if (strcmp(argv[1], "-f") == 0) {
        for (int i = 2; i < argc; ++i) {
            iret[i] = pthread_create( &files[i], NULL, check, argv[i]); // membuat thread pertama
        }
    }
    return 0;
}

void *check(char *argv[]) {
    pthread_t move, make;
    int types = 0;
    int imv, imk;
    char type[80] = {0};
    char *tok = NULL;

    tok = strtok(argv, ".");
    while (tok) {
        strcpy(type, tok);
        tok = strtok(NULL, ".");

        imv = pthread_create(&make, NULL, mkdir, argv);

        imk = pthread_create(&move, NULL, mvdr, argv);

        pthread_join(mkdir, NULL);
        pthread_join(mvdr, NULL);
    }
}

void *mkdir(char *argv[]) {
    child = fork();

    if (child == 0) {
        char *mkdr[3] = { "mkdir", argv, NULL };
        execv("/usr/bin/mkdir", mkdr);
    }
}

void *mvdr(char *argv[]) {
    child = fork();

    if (child == 0) {
        char *mv[5] = { "mv", "-v", argv, argv, NULL };
        execv("/usr/bin/mv", mv);
    }
}

I'm using execv to make and move files. It has to be related to threading, pipes, or sockets. Do you have any clue how to solve it? Your help is much appreciated

It isn't clear what constraints are placed on the classroom exercise, and my Indonesian is not as good as the OP's English, and Chrome didn't seem willing to translate the README.md file on the GitHub page https://github.com/VYPRATAMA009/sisop-modul-3 .

Tackling the problem as described in the question (in terms of the desired result), there is no need to use either threads or fork() and exec*() to implement the program.

It is almost invariably a bad idea to mix threads with fork() and exec*() — choose multi-threading or multi-processing but not both at once.

The program needs to process the option ( -f to check for regular files only; omit to move any file type), and then process any residual file names. The name processing consists of checking for a regular file if desired, finding the extension with strrchr() , then creating a directory with that extension name, then formatting the name in the sub-directory, then renaming the file so it goes into the directory, and freeing the allocated memory.

#include "stderr.h"
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

static bool is_regular(const char *filename);
static void mk_directory(const char *dirname);
static void move_file(const char *filename);

static bool check_file = false;

static const char usestr[] = "[-f] file [...]";
static const char optstr[] = "f";

int main(int argc, char *argv[])
{
    int opt;
    err_setarg0(argv[0]);

    while ((opt = getopt(argc, argv, optstr)) != -1)
    {
        switch (opt)
        {
        case 'f':
            check_file = true;
            break;
        default:
            err_usage(usestr);
            /*NOTREACHED*/
        }
    }

    if (optind == argc)
        err_usage(usestr);

    for (int i = optind; i < argc; i++)
        move_file(argv[i]);

    return 0;
}

static bool is_regular(const char *filename)
{
    struct stat sb;
    if (stat(filename, &sb) != 0)
        err_syserr("failed to get status of file '%s': ", filename);
    return S_ISREG(sb.st_mode);
}

static void mk_directory(const char *dirname)
{
    if (mkdir(dirname, 0755) != 0)
    {
        if (errno != EEXIST)
            err_syserr("failed to create directory '%s': ", dirname);
    }
}

static void move_file(const char *filename)
{
    char *dot = strrchr(filename, '.');
    if (check_file && !is_regular(filename))
    {
        err_remark("'%s' is not a regular file\n", filename);
        return;
    }
    if (dot == NULL || dot == filename || dot[1] == '\0')
    {
        err_remark("file '%s' does not have an extension\n", filename);
        return;
    }
    mk_directory(dot + 1);
    size_t namelen = strlen(dot + 1) + strlen(filename) + sizeof("/");
    char *buffer = malloc(namelen);
    if (buffer == NULL)
        err_syserr("failed to allocated %zu bytes memory: ", namelen);
    sprintf(buffer, "%s/%s", dot + 1, filename);
    if (rename(filename, buffer) != 0)
        err_syserr("failed to rename '%s' to '%s': ", filename, buffer);
    free(buffer);
}

This uses my error reporting functions which are available in my SOQ (Stack Overflow Questions) repository on GitHub as files stderr.c and stderr.h in the src/libsoq sub-directory.

Given a directory that starts out containing:

$ ls -la
total 56
drwxr-xr-x   15 jonathanleffler  staff   480 Apr  2 22:14 .
drwxr-xr-x  241 jonathanleffler  staff  7712 Apr  2 22:16 ..
-rw-r--r--    1 jonathanleffler  staff     0 Apr  2 22:12 .junk
-rw-r--r--    1 jonathanleffler  staff     0 Apr  2 22:12 .junk.
-rw-r--r--    1 jonathanleffler  staff  1036 Apr  2 22:06 binge.c
-rw-r--r--    1 jonathanleffler  staff   666 Apr  2 22:06 garbage.c
-rw-r--r--    1 jonathanleffler  staff  1772 Apr  2 21:11 junk-0.0.1.tar.gz
-rw-r--r--    1 jonathanleffler  staff  1772 Apr  2 21:10 junk-1.txt
-rw-r--r--    1 jonathanleffler  staff  1772 Apr  2 21:10 junk-2.txt
-rw-r--r--    1 jonathanleffler  staff     0 Apr  2 22:12 junk.
-rw-r--r--    1 jonathanleffler  staff  1772 Apr  2 21:10 junk.c
drwxr-xr-x    3 jonathanleffler  staff    96 Apr  2 22:04 junk.dir
prw-r--r--    1 jonathanleffler  staff     0 Apr  2 22:10 junk.fifo
lrwxr-xr-x    1 jonathanleffler  staff     8 Apr  2 21:12 junk.lnk -> junk.dir
-rw-r--r--    1 jonathanleffler  staff   812 Apr  2 22:06 trash.c
$

running the program ( mf29 compiled from mf29.c ) yields:

$ mf29 -f .j* *
mf29 -f .j* *
mf29: file '.junk' does not have an extension
mf29: file '.junk.' does not have an extension
mf29: file 'junk.' does not have an extension
mf29: 'junk.dir' is not a regular file
mf29: 'junk.fifo' is not a regular file
mf29: 'junk.lnk' is not a regular file
$ ls -la
total 0
drwxr-xr-x   11 jonathanleffler  staff   352 Apr  2 22:37 .
drwxr-xr-x  241 jonathanleffler  staff  7712 Apr  2 22:16 ..
-rw-r--r--    1 jonathanleffler  staff     0 Apr  2 22:12 .junk
-rw-r--r--    1 jonathanleffler  staff     0 Apr  2 22:12 .junk.
drwxr-xr-x    6 jonathanleffler  staff   192 Apr  2 22:37 c
drwxr-xr-x    3 jonathanleffler  staff    96 Apr  2 22:37 gz
-rw-r--r--    1 jonathanleffler  staff     0 Apr  2 22:12 junk.
drwxr-xr-x    3 jonathanleffler  staff    96 Apr  2 22:04 junk.dir
prw-r--r--    1 jonathanleffler  staff     0 Apr  2 22:10 junk.fifo
lrwxr-xr-x    1 jonathanleffler  staff     8 Apr  2 21:12 junk.lnk -> junk.dir
drwxr-xr-x    4 jonathanleffler  staff   128 Apr  2 22:37 txt
$

Then reinstating the moved files and running again without the -f option yields:

$ mv ?/* ??/* ???/* ????/* .
$ rmdir ? ?? ??? ????
$ mf29 .j* *
mf29: file '.junk' does not have an extension
mf29: file '.junk.' does not have an extension
mf29: file 'junk.' does not have an extension
$ ls -la
total 0
drwxr-xr-x   11 jonathanleffler  staff   352 Apr  2 22:42 .
drwxr-xr-x  241 jonathanleffler  staff  7712 Apr  2 22:16 ..
-rw-r--r--    1 jonathanleffler  staff     0 Apr  2 22:12 .junk
-rw-r--r--    1 jonathanleffler  staff     0 Apr  2 22:12 .junk.
drwxr-xr-x    6 jonathanleffler  staff   192 Apr  2 22:42 c
drwxr-xr-x    3 jonathanleffler  staff    96 Apr  2 22:42 dir
drwxr-xr-x    3 jonathanleffler  staff    96 Apr  2 22:42 fifo
drwxr-xr-x    3 jonathanleffler  staff    96 Apr  2 22:42 gz
-rw-r--r--    1 jonathanleffler  staff     0 Apr  2 22:12 junk.
drwxr-xr-x    3 jonathanleffler  staff    96 Apr  2 22:42 lnk
drwxr-xr-x    4 jonathanleffler  staff   128 Apr  2 22:42 txt
$

If you provide names with multiple pathname components, this will usually fail:

$ ../mf29 ~/src/cmd/timecmd.c
mf29: failed to rename '/Users/jonathanleffler/src/cmd/timecmd.c' to 'c//Users/jonathanleffler/src/cmd/timecmd.c': error (2) No such file or directory
$

There are various ways that could be fixed — it depends on the desired result. The POSIX function basename() could be useful. The function mkpath() could be useful too.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM