Προς το περιεχόμενο

Μια βοήθεια αν μπορείτε...


georginos1989

Προτεινόμενες αναρτήσεις

Δημοσ.

Έχω τα 2 προγράμματα που φαίνονται παρακάτω. Και τα 2 το ίδιο ειναι απλώς ειναι λυμμένα με διαφορετικό τρόπο. Αυτό που θέλω είναι το πως θα ξεχωρίζει το πρόγραμμα πότε αυτό που διαβάζει είναι φάκελος ή υποφάκελος ή αρχείο;

Δηλαδή διαβάζει τα περιεχόμενα ενός φακέλου, μετά πως θα ξέρει αν υπάρχει υποφάκελος μέσα ώστε να μπεί μέσα σαυτόν και να διαβάσει τα περιεχόμενά του;

Το πρώτο:

#include<stdio.h>

#include<dirent.h>

#include<dos.h>

#include<io.h>

#include<direct.h>

#include<string.h>

 

void show_directory (char *directory_name[20])

{

DIR *directory_pointer;

struct dirent *entry;

unsigned attributes;

 

if ((directory_pointer = opendir(directory_name)) == NULL)

printf("error opening %s\n", directory_name);

else

{

chdir(directory_name);

while (entry = readdir(directory_pointer))

{

attributes = _chmod(entry,0);

 

if ((attributes & FA_DIREC) &&

(strncmp(entry, ".",1) != 0))

{

printf("\n\n----%s----\n", entry);

show_directory(entry);

}

else

printf("%s\n", entry);

}

closedir(directory_pointer);

chdir("..");

}

}

 

Το δεύτερο:

 

#include<stdio.h>

#include<dirent.h>

main()

{

struct DIR *input_directory;

struct dirent *directory_pointer;

unsigned attr;

char name[20];

if ((input_directory = opendir("c:\\a\\")) ==NULL)

{

printf ("Error \n");

while( directory_pointer = readdir(input_directory))

{

printf("%s\t\n", directory_pointer);

}

}

else

printf("geia");

while( directory_pointer = readdir(input_directory))

{

printf("%s\t\n", directory_pointer);

}

closedir(directory_pointer);

getch();

}

Δημοσ.

Το πρώτο πρόγραμμα χρησιμοποιεί την _chmod η οποία επιστρέφει μια σειρά από τιμές που περιγράφουν το τι είναι κάθε στοιχείο του file-system.

 

Αν είναι FA_DIREC τότε πρόκειται για κατάλογο οπότε η ρουτίνα καλεί τον εαυτό της σε αυτόν τον κατάλογο.

 

Για περισσότερα δες την _chmod.

Δημοσ.

Στη σύγκριση if ((attributes & FA_DIREC) && (strncmp(entry, ".",1) != 0)) το & τι σημαίνει;

το && ξέρω ότι είναι το and..

 

 

-----Προστέθηκε 9/12/2008 στις 06 : 15 : 38-----

 

 

Με την if ((directory_pointer = opendir(directory_name)) == NULL)

printf("error opening %s\n", directory_name); τι ελεγχουμε; Το & τι σημαίνει; Το && ξέρω ότι είναι το and...

Δημοσ.

if ((attributes & FA_DIREC) && (strncmp(entry, ".",1) != 0))

 

Λέει ότι αν το στοιχείο είναι directory ( & είναι bit-wise AND - μην το μπλέκεις ποτέ με το && που είναι logic AND) και αν δεν αρχίζει η ονομασία του από . τότε εκτέλεσε τον κώδικα.

 

Αυτό το κάνει διότι το σύστημα (πχ. Windows) επιστρέφουν δυο εικονικά directory τα . & .. τα οποία οδηγούν το πρώτο στο τρέχον directory και το δεύτερο στο γονέα του directory οπότε η ρουτίνα θέλει να τα αποφύγει (αλλά και εδώ μπορεί να υπάρχει ένα bug στο strncmp αλλά ας το αφήσουμε for now -πχ. στα windows μπορείς να έχεις ένα ".t" directory).

Δημοσ.

Ααα μάλιστα.. Εγώ βασικά θέλω το πρόγραμμα να διαβάζει τα περιεχόμενα ενός φακέλου να τα εμφανίζει. Κάθε φορα που είναι υποφάκελος να μπαίνει πιο μέσα στην οθόνη και να εμφανίζει τα περιεχόμενα του..

Ξέρετε πως θα γίνει αυτό;

 

 

-----Προστέθηκε 9/12/2008 στις 09 : 35 : 01-----

 

 

Ξέρει κανένας;

Πχ να εμφανίζει πρώτα τον αρχικό φάκελο και αποκάτω και λιγο πιο μεσα τον υποφάκελο με τα αρχεία και αν εχει κιαλο υποφάκελο παλι λιγο πιο μεσα.....

Δημοσ.

Μια απλή σκέψη είναι να εκτυπώνεις κενούς χαρακτήρες δίπλα από τα στοιχεία που προβάλεις στην οθόνη (stdout), σπρώχνοντας τα έτσι προς τα δεξιά.

 

Μπορείς να αυξάνεις των αριθμό των κενών αυτών χαρακτήρων κάθε φορά που μπαίνεις σε ένα directory ενώ αντίστροφα μπορείς να τους μειώνεις κάθε φορά που βγαίνεις από αυτό.

 

Παρακάτω ακολουθεί η εφαρμογή της παραπάνω σκέψης. Η show_directory τώρα δέχεται μια ακόμη παράμετρο τύπου *int στην οποία αποθηκεύεται ο αριθμός των κενών που πρέπει να εκτυπωθούν με βάση την είσοδο αλλά και έξοδο της από directories. Μια ακόμη αλλαγή στην show_directory είναι η χρήση της ρουτίνας printright που εκτυπώνει τα ανάλογα κενά πριν την ονομασία του προς εκτύπωση στοιχείου.

 

Ο κώδικας είναι πειραματικός (concept) και πρέπει να μελετήσεις τα σχόλια που έχω συμπεριλάβει, δεν λαμβάνει υπόψη του περιπτώσεις παρουσίασης σφάλματος ώστε να προσαρμόζει ανάλογα τον αριθμό των κενών (pnRight).

 

Τέλος έχω τροποποιήσει μερικά πράγματα (όπως η αλλαγή της strncmp με strcmps για . & ..) δίχως να σημαίνει όμως ότι είναι bug-free, αντίθετα προτείνω εκτενές debugging.

 

>
#include <stdio.h>
#include <dirent.h>
#include <dos.h>
#include <io.h>
#include <direct.h>
#include <string.h>

void show_directory (char *directory_name, int *pnRight);
void printright(int *nIdent);

int main(int argc, char *argv[])
{
int	nRight = 0;
   /* Αν δεν υπάρχει Option ψάξε το παρόν (.) directory */
show_directory((argc == 1) ? ".": argv[1], &nRight);

return	0;
}

void show_directory (char *directory_name, int *pnRight)
{
DIR *directory_pointer;
struct dirent *entry;
unsigned attributes;

if ((directory_pointer = opendir(directory_name)) == NULL)
	printf("error opening %s\n", directory_name);
else
 {
	chdir(directory_name);
	while ((entry = readdir(directory_pointer)) != NULL)
	 {
		attributes = _chmod(entry->d_name,0);

		/* Αφαίρεση του strncmp . με το πιο συνεπές για Windows strcmp . & .. */
		if ((attributes & FA_DIREC) && strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
		 {
			/* Εκτυπώνουμε pnRight κενούς χαρακτήρες στο stdout */
			printright(pnRight);
			/* Εκτυπώνουμε το όνομα του κατάλογου */
			printf("[%s]\n", entry->d_name);

			/* Αυξάνουμε το βάθος +1 χαρακτήρα δεξιά για τα υπόλοιπα στοιχεία */
			*pnRight = *pnRight + 1;

			show_directory(entry->d_name, pnRight);
		 }
		else
		 {
			/* Εκτυπώνουμε pnRight κενούς χαρακτήρες στο stdout */
			printright(pnRight);
			/* Εκτυπώνουμε το όνομα του αρχείου */
			printf("%s\n", entry->d_name);
		 }
	 }
	closedir(directory_pointer);
	chdir("..");

	/*
	 * Γυρίσαμε πίσω κατά έναν κατάλογο (επιτυχώς ή όχι) -
	 * αφαιρούμε 1 χαρακτήρα από το βάθος όσο pnRigt > 0.
	 */
	if(*pnRight > 0)
		*(int*)pnRight = *(int*)pnRight - 1;
}
}

void printright(int *nRight)
{
/*
 * Προσθέτει nRight κενά στο szIdent char array και ύστερα το εκτυπώνει
 * στο stdout δίχως αλλαγή γραμμής. Το szIdent έχει μέγεθος BUFSIZ που
 * συνήθως είναι αρκετό για μια τυπική directory->subdirectory->subdir..
 * δομή λογικού βάθους
 */
static char szIdent[bUFSIZ];

/* Μηδενίζουμε το szIdent */
memset(&szIdent, 0, sizeof(szIdent));
/* Αυξάνουμε το szIdent άμεσα κατά nRight ' ' */
memset(&szIdent, ' ', (*nRight) * sizeof(char));
/* Εκτύπωση */
printf("%s", szIdent);
}

 

Η έξοδος του για μια απλή directory δομή:

 

>
.
..
[.bug]
.
..
out
[A]
.
..
[A1]
 .
 ..
 out
out
[b]
.
..
out
[C]
.
..
out
main.obj
mytree.cgl
mytree.exe
mytree.map
mytree.tds
out
output

 

Ο κώδικας δοκιμάσθηκε με απλά directories σε CodeGear C++ Builder.

 

Καλή τύχη!

Δημοσ.

Έχω μερικές απορίες

Που βάζεις το path του φακέλου που θες να διαβάσει;

Οι μεταβλητές argc kai argv τι αποθηκεύουν;

Δεν έχω καταλάβει τα ορίσματα όταν καλούμε τη show_directory.

Τι σημαίνει το βελάκι εδώ; (entry->d_name)

Εδώ if(*pnRight > 0)

*(int*)pnRight = *(int*)pnRight - 1; γιατί γράφεις *(int*) ;

Τί είναι τα stdout, szident kai memset

 

 

-----Προστέθηκε 10/12/2008 στις 09 : 54 : 39-----

 

 

Sorry που ρωτάω πολλά αλλά ακόμα δεν έχουμε κάνει τέτοια πράγματα..

Αν μπορείται να με βοηθήσετε μέχρι σήμερα...

Ευχαριστώω...

Δημοσ.

@Gtroza:

Καλές γιορτές και σε ένα φίλε μου!! :)

 

Έχω μερικές απορίες

Που βάζεις το path του φακέλου που θες να διαβάσει;

Οι μεταβλητές argc kai argv τι αποθηκεύουν;

Δεν έχω καταλάβει τα ορίσματα όταν καλούμε τη show_directory.

Τι σημαίνει το βελάκι εδώ; (entry->d_name)

Εδώ if(*pnRight > 0)

*(int*)pnRight = *(int*)pnRight - 1; γιατί γράφεις *(int*) ;

Τί είναι τα stdout, szident kai memset

 

 

-----Προστέθηκε 10/12/2008 στις 09 : 54 : 39-----

 

 

Sorry που ρωτάω πολλά αλλά ακόμα δεν έχουμε κάνει τέτοια πράγματα..

Αν μπορείται να με βοηθήσετε μέχρι σήμερα...

Ευχαριστώω...

 

Θα προσπαθήσω να στα εξηγήσω όσο πιο απλά μπορώ – οπότε οι υπόλοιποι ας συγχωρήσουν τις απλοποιήσεις μου.

 

Οι μεταβλητές argc kai argv τι αποθηκεύουν;

 

Καταρχήν, τα argc και argv μας επιτρέπουν να διαβάζουμε τις παραμέτρους που περνά ο χρήστης στο πρόγραμμα μας.

 

Ας υποθέσουμε ότι το πρόγραμμα μας το έχουμε ονομάσει MyTree και θέλουμε να φτιάξουμε το δένδρο για τους καταλόγους του δίσκου D, δίνουμε στην κονσόλα:

 

>
MyTree D:\

 

Το argc μας δίνει τον αριθμό των παραμέτρων που έχουμε περάσει στο πρόγραμμα ενώ το argv είναι ένας πίνακας (char*) που περιέχει τις παραμέτρους αυτές (δηλαδή το “D:\”).

 

Εδώ φίλε μου πρέπει να έχεις υπόψη σου μια σημαντική λεπτομέρεια. Όταν το argc είναι ίσον με 1 τότε ο χρήστης δεν έχει περάσει καμία παράμετρο στο πρόγραμμα – στο λέω διότι πολύς κόσμος μπερδεύετε και νομίζει ότι αν το argc == 1 τότε ο χρήστης έχει περάσει μια παράμετρο στο πρόγραμμα, αλλά δεν είναι έτσι. Ο χρήστης περνά δικές του παραμέτρους στο πρόγραμμα αν argc > 1. Γιατί; Διότι η C περνά αυτόματα ως πρώτη εικονική – ψεύτικη αν θες παράμετρο στο πρόγραμμα το πλήρες path από το οποίο εκτελείται (αυτή η παράμετρος αποθηκεύεται στο argv[0] –θυμήσου ότι μετράμε από το μηδέν στην C όταν δουλεύουμε με arrays).

 

Που βάζεις το path του φακέλου που θες να διαβάσει;

 

Το path του φακέλου που θέλω να διαβάσω το τοποθετώ εδώ:

 

>
show_directory((argc == 1) ? ".": argv[1], &nRight);

 

Τι λέω τώρα εδώ πέρα; Λέω στο πρόγραμμα (με την βοήθεια του τελεστή ? -ελπίζω να τον έχετε διδαχτεί!) ότι αν το argc είναι ίσο με 1 τότε το πρόγραμμα θα πρέπει να διαβάσει το τρέχον directory στο οποίο βρίσκεται το εκτελέσιμο του (Θυμήσου από τα παραπάνω ότι αν argc == 1 δεν υπάρχει παράμετρος χρήστη στο πρόγραμμα). Το τρέχον directory συμβολίζεται σε MS-DOS & MS-Windows με τον χαρακτήρα “.” (τελεία) ο οποίος θα είναι το path μας. Αν το argc δεν είναι 1 τότε χρησιμοποιώ ως path την πρώτη παράμετρο που έχει περάσει ο χρήστης στο προγράμμα και που βρίσκεται αποθηκευμένη στον πίνακα argv στην θέση [1] (και στο παράδειγμα μας είναι το D:\).

 

Αν σε δυσκολεύουν όλα αυτά, μπορείς απλά να αλλάξει το

>show_directory((argc == 1) ? ".": argv[1], &nRight);

με ότι άλλο σε εξυπηρετεί. Για παράδειγμα show_directory(mypath, &nRight) και δήλωσε το mypath διαφορετικά, όπως σε διευκολύνει αφού δεν είστε προχωρημένοι στην C.

 

--

Δεν έχω καταλάβει τα ορίσματα όταν καλούμε τη show_directory

 

Το πρώτο όρισμα είναι ένα char* αυτό πρέπει να το γνωρίζεις από την σχολή σου, είναι βασικό. Ουσιαστικά πρόκειται για ένα char array μόνο που είναι δείκτης σε αυτό. Για παράδειγμα: char szMyPath[bUFSIZ] => show_directory(&szMyPath, &nRight);.

Το δεύτερο όρισμα είναι ένα int* και αυτό πρέπει να το γνωρίζεις από την σχολή σου. Ουσιαστικά πρόκειται για ένα int μόνο που είναι δείκτης. Αυτός ο δείκτης κρατά συνεχώς το πόσα κενά θα πρέπει να βάλουμε πριν την εκτύπωση κάθε στοιχείου στην οθόνη μας ώστε να πηγαίνει προς τα δεξιά.

 

--

Τι σημαίνει το βελάκι εδώ; (entry->d_name)

 

Δυστυχώς εδώ βλέπω μεγάλα κενά. Το βελάκι το χρησιμοποιούμε για να προσπελάσουμε τα περιεχόμενα ενός struct* δηλαδή ενός struct pointer. Αν το struct μας δεν είναι pointer χρησιμοποιούμε αντί για βελάκι μια τελεία . (πχ. entry.d_name) όμως καθώς η readdir μας επιστρέφει ένα struct* χρησιμοποιούμε το -> για να μάθουμε το όνομα (d_name) του στοιχείου (entry) που έχει βρει. Η παλιά σύνταξη που χρησιμοποιούσες είναι μη αποδεκτή σε ορθή C και έδινε warnings στον compiler (ακόμα και αν λειτουργούσε).

 

--

Εδώ if(*pnRight > 0)

*(int*)pnRight = *(int*)pnRight - 1; γιατί γράφεις *(int*) ;

 

Γράφω *(int*) για να ξεκαθαρίσω στον αναγνώστη και φυσικά στον Compiler πέραν πάσης αμφιβολίας ότι επιθυμώ να αυξήσω την τιμή των δεδομένων της διεύθυνσης pnRight και όχι απλά την ίδια την διεύθυνση του pnRight -καθώς το pnRight είναι pointer.

 

--

Τί είναι τα stdout, szident kai memset

 

Το stdout είναι η έξοδος του προγράμματος – η οθόνη (μπορεί να την ανακατευθύνουμε και άλλου αλλά ας πούμε ότι είναι η οθόνη και τέλος).

Το szIdent είναι ένα char/string το οποίο γεμίζω με κενά και εκτυπώνω πριν την ονομασία των αρχείων ώστε να πηγαίνουν προς δεξιά όσες θέσεις είναι απαραίτητο.

Το memset είναι μια εντολή που γεμίζει μπλοκ μνήμης με όσους χαρακτήρες θέλουμε. Οπότε κάνω ένα μικρό τρικ και λέω, αντί να γράφω ένα loop που θα εκτυπώνει τόσα κενά στην οθόνη, θα γεμίζω το szIdent με τόσα κενά όσα χρειάζονται κάθε φορά και ύστερα θα τα εκτυπώνω αμέσως στην οθόνη.

 

Υ.Γ.

Δεν μπορώ να καλύψω τα κενά σου στην C – αυτά έπρεπε να τα κάλυπτε συστηματικά η σχολή σου καθώς όταν σας βάζει τέτοιου είδους ασκήσεις υποτίθεται ότι κατέχεται κάποια πράγματα σε C και στα Λ.Σ. (για παράδειγμα πως σας ζητάνε να γράψετε μια εντολή σαν την MS-DOS Tree αν δεν σας διδάξουν τα argc και argv; ) Πράγματα που φαίνεται ότι δεν κατέχεις όμως οπότε μου κάνει εντύπωση το πώς σας ζήτησαν τέτοια θέματα .. anyway.

Δημοσ.

Ευχαριστώ πολύ που βοηθάς...

Μια τελευταία ερώτηση. αν χρησιμοποιήσω τη show_directory(mypath, &nRight) έτσι, θα διαβάζω το mypath me scanf ε; Τα argc argv δε χρειάζονται να τα βάλω ε;

 

Αυτό που λες στο τέλος ότι δεν μας τα διδάσκουν είναι αλήθεια. Τους το έχουμε πει πόσες φορές αλλά ποιος μας ακούει. Και το καλύτερο είναι ότι όταν τους ζητάμε βοήθεια δεν μας βοηθάν.

Τη μια λένε δεν ξέρω, την άλλη αυτά τα ξέρετε μη ρωτάτε...Ελεος δηλαδή....

 

 

-----Προστέθηκε 10/12/2008 στις 11 : 30 : 05-----

 

 

Άκυρη η ερώτηση.. Το βρήκα...

Το δοκίμασα σε ένα φάκελο δικό μου ο οποίος έχει 2 αρχεία μέσα και ενα υποφάκελο α ο οποίος α έχει ενα αρχείο και ένα υποφάκελο β ο οποίος β έχει ενα αρχείο

Το πρόγραμμα εμφανίζει τον [α] απο κάτω και πιο μεσα τον [β] απο κάτω το αρχείο του β και από κάτω και λίγο πιο έξω το αρχείο του α

και μετα απο κάτω και πιο έξω πάλι τα αρχεία του αρχικού φακέλου.

Δε λέω εντάξι είναι.. αλλά μήπως γίνεται το αρχείο του [α] να εμφανίζεται κάτω απο τον [α] και όχι μετα τον [β] ?

Αντί να τυπώνει κενά μπορούμε να το κάνουμε να τυπώνει κάτι άλλο πχ παύλες?

Αν θέλουμε να εμφανίζει μόνο τους φακέλους χωρίς τα αρχεία τι απαλοίφουμε από το πρόγραμμα?

Δημοσ.

αλλά μήπως γίνεται το αρχείο του [α] να εμφανίζεται κάτω απο τον [α] και όχι μετα τον [β] ?

 

Γίνεται αλλά είναι μάλλον μπελαλίδικο. Οπότε αν δεν υπάρχει ιδιαίτερος λόγος βασίσου στην ιεράρχηση που κάνει αυτόματα το readdir και το λειτουργικό σύστημα που την τροφοδοτεί με κατάλογους και αρχεία.

 

Αντί να τυπώνει κενά μπορούμε να το κάνουμε να τυπώνει κάτι άλλο πχ παύλες?

 

Μπορείς αντικαθιστώντας το:

>
memset(&szIdent, ' ', (*nRight) * sizeof(char));

με

>
memset(&szIdent, '-', (*nRight) * sizeof(char));

 

Αν θέλουμε να εμφανίζει μόνο τους φακέλους χωρίς τα αρχεία τι απαλοίφουμε από το πρόγραμμα?

 

το:

 

>
		else
		 {
			/* Εκτυπώνουμε pnRight κενούς χαρακτήρες στο stdout */
			printright(pnRight);
			/* Εκτυπώνουμε το όνομα του αρχείου */
			printf("%s\n", entry->d_name);
		 }

Δημοσ.

Ευχαριστώ και πάλι...

Αφού είναι δύσκολο αυτό με την ιεράρχηση άστο....

Μπορεί να δοκιμάσω τπτ εγώ στο πρόγραμμα το πρώτο που είχα κάνει. Μπορεί να βρώ κανένα συνδιασμό γιατί εκείνο εμφάνιζε τον φάκελο και απο κάτω τα αρχεία.. Θα το κοιτάξω και αν δε βρω τπτ θα το αφήσω έτσι..

Αν το θέλουν αυτοί διαφορετικά ας μας το μάθαιναν πρώτα και μετά να μας έβαζαν την άσκηση...

Για να ξέρεις.. ΤΟ πρόγραμμα θα μοιάζει με την εντολή tree του ms-dos..

Ευχαριστώ και πάλι για τη βοήθεια....

 

 

-----Προστέθηκε 10/12/2008 στις 12 : 50 : 01-----

 

 

Κάτι τελευταίο.. Οι . και .. που εμφανίζονται είναι λόγω της readdir ε?

Δημοσ.

Ωραίαα.... Ευχαριστώ για την όλη βοήθεια....

 

 

-----Προστέθηκε 11/12/2008 στις 12 : 27 : 41-----

 

 

Μπορείς να πεις τι κάνει η chdir;

 

 

-----Προστέθηκε 11/12/2008 στις 10 : 13 : 12-----

 

 

Ξέρει κανένας;

Αρχειοθετημένο

Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...