怎樣用C語言對某個目錄下的文件名進行排序?
在4.8的例子中,用_dos_findfirst()和_dos_findnext()函數遍歷目錄結構,每找到一個文件名,就把它打印在屏幕上,因此,文件名是逐個被找到并列出來的。當你對某個目錄下的文件名進行排序時,這種逐個處理的方式是行不通的。你必須先將文件名存儲起來,當所有的文件名都找到后,再對它們進行排序。為了完成這項任務,你可以建立一個指向find_t結構的指針數組,這樣,每找到一個文件名,就可以為相應的find_t結構分配一塊內存,將其存儲起來。當所有的文件名都找到后,就可以用qsort()函數按文件名對所得到的find_t結構數組進行排序了。
qsort()函數是一個標準C庫函數,它有4個參數:指向待排數組的指針,待排元素的數目,每個元素的大小,指向用來比較待排數組中兩個元素的函數的指針。比較函數是你要提供的一個用戶自定義函數,根據所比較的第一個元素是大于、小于或等于第二個元素,它將返回一個大于、小于或等于0的值。請看下例:
#include <stdio.h>
#include <direct.h>
#include <dos.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
typedef struct find_t FILE_BLOCK ;
int sort_files(FILE_BLOCK * * , FILE-BLOCK * * );
void main(void);
void main(void)
{
????? FILE_BLOCK f_block;??????? /* Define the find_t structure variable * /
????? int ret_code;????????????? /* Define a variable to store the retur
????????????????????????????????????????????????? codes * /
????? FILE_BLOCK * * file_block; /* Used to sort the files * /
????? int file_count;??????????? / * Used to count the flies * /
????? int x;???????????????????? / * Counter variable * /
????? file_count = -1;
????? / * Allocate room to hold up to 512 directory entries.? * /
????? file_list = (FILE_BLOCK * * ) malloc(sizeof(FILE_BLOCK * ) * 512);
????? printf("\nDirectory listing of all files in this directory ; \n\n");
????? / * Use the " *. * " file mask and the 0xFF attribute mask to list
??????????? all files in the directory, including system files, hidden
??????????? files, and subdirectory names.? * /
????? ret_code = _dos_findfirst(" *.* ", 0xFF, &f_block);
????? / * The _dos_findfirst() function returns a 0 when it is successful
????????? and has found a valid filename in the directory.? * /
????? while (ret_code == 0 && file_count < 512)
????? {
?????????? / * Add this filename to the file list * /
?????????? file_list[++ file_count] =
???????????????? (FILE_BLOCK * ) malloc (sizeof(FILE_BLOCK));
??????????? * flile_list[file_count] = f_block;
?????????? /* Use the _dos_findnext() function to look
??????????????? for the next file in the directory.? * /
?????????? ret_code = _dos_findnext (&f_block);
????? }
????? /* Sort the files * /
????? qsort(file_list, file_count, sizeof(FILE_BLOCK * ), sort_files);
?????? / * Now, iterate through the sorted array of filenames and
??????????? print each entry.? * /
????? for (x=0; x<file_count; x++)
????? {
?????????? printf(" %-12s\n", file_list[x]->name);
????? }
????? printf("\nEnd of directory listing. \n" );
}
int sort_files(FILE_BLOCK* * a, FILE_BLOCK* * b)
{
????? return (strcmp((*a)->name, (*b)->name));
}
在上例中,由用戶自定義的函數sort_files()來比較兩個文件名,它的返回值實際就是標準C庫函數strcmp()的返回值。只要相應地改變sort_files()函數的操作對象,上例就可按日期、時間或擴展名進行排序。?
怎樣用C語言列出一個文件的日期和時間?
在_dos_findirst()和_dos_findfnext()函數所返回的find_t結構中(請參見4.8),存放著查找到的文件的日期和時間,因此,只要對4.8中的例子稍作改動,就可以列出每個文件的日期、時間和文件名。文件的日期和時間存放在結構成員find_t.wr_date和find_t.wr_time中。文件的時間存放在一個雙字節的無符號整數中,見下表:???
-------------------------------------------------------------???
? 元? 素??? 位域大小?????????????? 取值范圍
-------------------------------------------------------------
??? 秒??????? 5位???????????? 0—29(乘以2后為秒值)
??? 分??????? 6位???????????? 0—59
??? 時??????? 5位???????????? 0—23
-------------------------------------------------------------
文件的日期同樣也存放在一個雙字節的無符號整數中,見下表:
-------------------------------------------------------------
? 元? 素??? 位域大小???????????? 取值范圍
-------------------------------------------------------------
??? 日??????? 5位????????????? ? 1—31
??? 月??????? 4位??????????????? 1—12???
??? 年??????? 7位????????????? ? 1--127(加上1980后為年值)
-------------------------------------------------------------
因為DOS存儲文件的秒數的間隔為兩秒,所以只需使用0--29這個范圍內的值。此外,DOS產生于1980年,因此文件的日期不可能早于1980年,你必須加上“1980”這個值才能得到真正的年值。
以下是列出某個目錄下所有的文件及其日期和時間的一個例子:
#include <stdio.h>
#include <direct.h>
#include <dos. h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
typedef struct find_t FILE_BLOCK
void main(void);
void main(void)
{
????? FILE_BLOCK f_block;? /* Define the find-t structure variable * /
????? int ret-code;??????? / * Define a variable to store return codes * /
????? int hour;??????????? / * We're going to use a 12-hour clockl * /
????? char * am_pm;??????? / * Used to print "am" or "pm" * /
????? printf("\nDireetory listing of all files in this directory:\n\n");
????? / * Use the ' *. * ' file mask and the 0xFF attribute mask to list
?????????? all files in the directory, including system files, hidden
?????????? files, and subdirectory names.? * /
????? ret_code = _dos_findfirst(" *.* ", 0xFF, &f_block);
/* The_dos_findfirst() function returns a 0 when it is successful
? and has found a valid filename in the directory.? * /
??? while (ret_code == 0)
??? {
???????? / * Convert from a 24-hour format to a 12-hour format.? * /
???????? hour = (f_block. wr_time>>11);
???????? if (hour > 12)
???????? {
????????????? hour = hour - 12;
????????????? am_pm = "pm";
???????? }
???????? else
????????????? am_pm="am";
???????? / * Print the file's name, date stamp, and time stamp.? * /
???????? printf("%-12s %2d/%2d/%4d? %2d:%2d:%02d %s\n",
????????????????????? f_block.name,??????????????????????? / * name * /
????????????????????? (f-block.wr_date >> 5) & 0x0F,?????? / * month * /
????????????????????? (f_block.wr_date) & 0x1F,??????????? / * day?? * /
????????????????????? (f_block.wr_date >> 9) + 1980 ,????? / * year * /
????????????????????? hour,??????????????????????????????? / * hour * /
????????????????????? (f-block. wr_time >> 5) & 0x3F,????? / * minute * /
????????????????????? (f_block. wr_time & 0x1F) * 2,?????? / * seconds * /
????????????????????? am_pm);
???????? /* Use the _ dos_findnext() function to look
????????????? for the next file in the directory.? * /
?
???????? ret_code = _dos_findnext (&f_block);
??? }
??? printf("\End of directory listing. \n" );
}
?? 請注意,為了獲得時間變量和日期變量的各個元素,要進行大量移位操作和位處理操作,如果你非常討厭這些操作,你可以自己定義一個find_t這樣的結構,并為C語言定義的find_t結構和你自己定義的結構創建一個共用體(請看下例),從而改進上例中的代碼。???
/ * This is the find_t structure as defined by ANSI C.? * /
struct find_t
{
???? char reserved[21];
???? char attrib;
???? unsigned wr_time;
??? unsigned wr_date;
???? long size;
???? char name[13];
/ * This is a custom find_t structure where we
???? separate out the bits used for date and time.? * /
struet my_find_t
{
???? char reserved[21];
???? char attrib;
???? unstgned seconds: 5;
???? unsigned minutes: 6;
???? unsigned hours: 5;
???? unsigned day: 5;
???? unstgned month: 4;
???? unsigned year: 7;
???? long size;
???? char name[13];
}
/* Now, create a union between these two strucures
?? so that we can more easily access the elements of
???? wr_date and wr_time.? * /
union file_info
{
????? struct find_t ft;
????? struct my_find_t mft;
}
用上例中的自定義結構和共用體,你就可以象下例這樣來抽取日期變量和時間變量的各個元素,而不必再進行移位操作和位處理操作了:
...
file_info my_file;
...
printf(" %-12s %2d/%2d/%4d %2d: %2d: %2d %s\n",
???????????? my_file, mfr.name,?????????????? / * name?????? * /
???????????? my-file, mfr.month,????????????? / * moth?????? * /
???????????? my_file, mfr.day,??????????????? / * day??????? * /
???????????? (my-file. mft.year + 1980),????? / * year?????? * /
???????????? my-file, raft. hours,??????????? / * hour?????? * /
???????????? my- file. mfr. minutes,????????? / * minute???? * /
???????????? (my_file. mft. seconds * 2),???? / * deconds??? * /
???????????? am_pm);
怎樣使用C語言列出某個目錄下的文件?
C語言本身沒有提供象dir_list()這樣的函數來列出某個目錄下所有的文件。不過,利用C語言的幾個目錄函數,你可以自己編寫一個dir_list()函數。???首先,頭文件dos.h定義了一個find_t結構,它可以描述DOS下的文件信息,包括文件名、時間、日期、大小和屬性。其次,C編譯程序庫中有_dos_findfirst()和_dos_findnext()這樣兩個函數,利用它們可以找到某個目錄下符合查找要求的第一個或下一個文件。???
dos_findfirst()函數有三個參數,第一個參數指明要查找的文件名,例如你可以用“*.*”指明要查找某個目錄下的所有文件。第二個參數指明要查找的文件屬性,例如你可以指明只查找隱含文件或子目錄。第三個參數是指向一個find_t變量的指針,查找到的文件的有關信息將存放到該變量中。???
dos_findnext()函數在相應的目錄中繼續查找由_dos_findfirst()函數的第一個參數指明的文件。_dos_findnext()函數只有一個參數,它同樣是指向一個find_t變量的指針,查找到剛文件的有關信息同樣將存放到該變量中。
利用上述兩個函數和find_t結構,你就可以遍歷磁盤上的某個目錄,并列出該目錄下所有的文件,請看下例:???
#include <stdio.h>
#include <direct.h>
#include <dos.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
typedef struct find_t FILE_BLOCK
void main(void);
void main(void)
{
????? FILE_BLOCK f-block;???????? /* Define the find_t structure variable * /
????? int?? ret_code;???????????? / * Define a variable to store the return codes * /
????? / * Use the "*.*" file mask and the 0xFF attribute mask to list
?????????? all files in the directory, including system files, hidden
?????????? files, and subdirectory names.? * /
????? ret_code = _dos_findfirst(" *. * ", 0xFF, &f_block);
????? /* The _dos_findfirst() function returns a 0 when it is successful
???????? and has found a valid filename in the directory.? * /
???? while (ret_code == 0)
???? {
????????? /* Print the file's name * /
????????? printf(" %-12s\n, f_block, name);
????????? / * Use the -dos_findnext() function to look
?????????????? for the next file in the directory.? * /
????????? ret_code = _dos_findnext (&f_block);
???? }
???? printf("\nEnd of directory listing. \n" );
}
(C語言)怎樣判斷是使用流函數還是使用低級函數?
流函數(如fread()和fwrite())帶緩沖區,在讀寫文本或二進制文件時效率更高。因此,一般來說,使用流函數比使用不帶緩沖區的低級函數(如read()和write())會使程序性能更好。然而,在多用戶環境中,文件需要共享,文件中的一部分會不斷地被加鎖、讀、寫或解鎖,這時流函數的性能就不如低級函數好,因為共享文件的內容變化頻繁,很難對它進行緩沖。因此,通常用帶緩沖區的流函數存取非共享文件,用低級函數存取共享文件。
文本模式(textmode)和二進制模式(binarymode)有什么區別?
流可以分為兩種類型:文本流和二進制流。文本流是解釋性的,最長可達255個字符,其中回車/換行將被轉換為換行符“\n”,反之亦然。二進制流是非解釋性的,一次處理一個字符,并且不轉換字符。???通常,文本流用來讀寫標準的文本文件,或者將字符輸出到屏幕或打印機,或者接受鍵盤的輸入;而二進制流用來讀寫二進制文件(例如圖形或字處理文檔),或者讀取鼠標輸入,或者讀寫調制解調器。
C語言stdout能被強制打印到非屏幕設備上嗎?
盡管標準流stdout的缺省方式是打印在屏幕上,但你可以將它重定向到其它設備上。請看下面的例子:? /* redir.c */
? #include<stdio.h>???
? void main(void);
? void main(void)
? {
????? printf(”Let's get redirectedI\n”),
? }
在DOS提示符下,通過重定向字符“>”,可以將上例對應的可執行程序的輸出重定向到非屏幕設備上。例如,下例將該程序的輸出重定向到prn設備(通常就是連接到LPTl端口的打印機)上:???
C:\>REDIR>PRN
同樣,你也可以將該程序的輸出重定向到一個文件上,請看下例:
??? C:\>REDIR>REDIR.OUT???
在上例中,原來在屏幕上顯示的輸出內容將全部寫入文件REDIR.OUT中。
怎樣恢復一個重定向了的標準流?
如果要將重定向了的標準流恢復到初始狀態,可以使用標準C庫函數dup()和fdopen()。dup()函數可以復制一個文件句柄,你可以用dup()函數保存對應于stdout標準流的文件句柄。fdopen()函數可以打開一個已用dup()函數復制了的流。這樣,你就可以重定向并恢復標準流,請看下例:???
#include <stdio.h>
void main(void);
void main(void)
{
??? int orig-stdout;
??? / * Duplicate the stdout file handle and store it in orig_stdout.? */
??? orig_stdout = dup (fileno (stdout));
??? / * This text appears on-screen.? * /
??? printf("Writing to original stdout... \n") ;
??? / * Reopen stdout and redirect it to the "redir. txt" file.? * /
??? freopen("redir.txt", "w", stdout);
??? / * This text appears in the "redir. txt" file.? * /
??? printf("Writing to redirected stdout.., \n");
??? /* Close the redirected stdout.? * /
??? fclose (stdout);
??? / * Restore the original stdout and print to the screen again.? * /
??? fdopen(orig_stdout, "w" );
??? printf("I'm back writing to the original stdout. \n");
}
C語言中,怎樣重定向一個標準流?
包括DOS在內的大多數操作系統,都提供了將程序的輸入和輸出重定向到不同設備上的手段。這就是說,程序的輸出并不一定是到屏幕上,還可以重定向到文件或打印機端口上;程序的輸入并不一定來自鍵盤,還可以重定向到文件上。在DOS中,重定向是通過重定向字符“<”和“>”來實現的。例如,如果你要求程序PRINTIT.EXE的輸入來自文件STRINGS.TXT,你就可以在DOS提示符下鍵入如下命令:
??? C:\>PRINTIT<STRINGS.TXT
請注意,可執行文件的名稱總是第一個出現。“<”符號告訴DOS將STRINGS.TXT中的字符串作為程序PRINTIT.EXE的輸入。關于重定向stdout標準流的例子請看4. 5。
標準流的重定向并不一定總在操作系統下進行,在程序內部,用標準C庫函數freopen()同樣可以重定向標準流。例如,如果你要求在程序內部將標準流stdout重定向到文件OUTPUT.TXT,你就可以象下面這樣使用freopen()函數:
??? freopen("output.txt","w",stdout);
現在,程序中每條輸出語句(例如prinft();puts(),putch()等)輸出的內容都將出現在文件OUTPUT.TXT中。
什么是文件流(stream)?
流是程序輸入或輸出的一個連續的字節序列,設備(例如鼠標、鍵盤、磁盤、屏幕、調制解調器和打印機)的輸入和輸出都是用流來處理的。在C語言中,所有的流均以文件的形式出現----不一定是物理磁盤文件,還可以是對應于某個輸入/輸出源的邏輯文件。C語言提供了5種標準的流,你的程序在任何時候都可以使用它們,并且不必打開或關閉它們。以下列出了這5種標準的流。------------------------------------------------
??? 名稱????????? 描? 述??????? ??? 例? 子
------------------------------------------------
??? stdin??????? 標準輸入?????????? 鍵盤
??? stdout?????? 標準輸出????????? ? 屏幕
??? stderr?????? 標準錯誤????????? ? 屏幕
??? stdprn?????? 標準打印機??????? ? LPT1端口
??? stdaux?????? 標準串行設備????? ? COM1端口
------------------------------------------------
需要注意的是,stdprn和stdaux并不總是預先定義好的,因為LPT1和COM1端口在某些操作系統中是沒有意義的,而stdin,stdout和stderr總是預先定義好的。此外,stdin并不一定來自鍵盤,stdout也并不一定顯示在屏幕上,它們都可以重定向到磁盤文件或其它設備上。
C語言中,當errno為一個非零值時,是否有錯誤發生?
許多標準的C庫函數都通過全局變量errno向程序傳遞一個錯誤號,以表明發生哪種錯誤,但是,你的程序不應該通過檢查errno的值來判斷是否發生了錯誤。通常,被調用的標準的C庫函數都有一個返回值,該值將表示是否發生了錯誤,并且表示是否已給errno賦予了相應的錯誤號。在沒有發生錯誤或所調用的函數不使用errno時,在errno中很可能仍然保留著一個錯誤號。有時,為了改善運行速度,使用errno的函數并不將errno清零。??總之,絕對不能單憑errno的值來判斷是否發生了錯誤,而應該根據函數的返回值來判斷是否應該檢查errno的值。請參考你所使用的編譯程序的有關文檔,看看哪些函數使用了errno全局變量,以及errno的有效值清單。