2010-02-13 31 views
34

Làm thế nào để xóa một thư mục trống trong C hoặc C++? Có chức năng nào không? rmdir chỉ xóa thư mục trống. Vui lòng cung cấp cách mà không cần sử dụng bất kỳ thư viện bên ngoài nào.Xóa một thư mục không trống trong lập trình C hoặc C++

Đồng thời cho tôi biết cách xóa tệp trong C hoặc C++?

+0

Mọi người sẽ downvote một câu hỏi mà họ không tìm thấy rõ ràng hoặc hữu ích. Vì câu hỏi của bạn dường như đủ rõ ràng, tôi đoán ai đó (không phải tôi) không thấy nó hữu ích. – Manuel

+5

Không có ngôn ngữ nào như C/C++ –

+1

Có lẽ nó đã bị bỏ qua vì câu hỏi đã được hỏi ở đây nhiều lần trước đây, ví dụ: http://stackoverflow.com/questions/1149764/delete-folder-with-items và mọi người bị bệnh khi nhìn thấy nó? Downvoter không phải là tôi, BTW. –

Trả lời

21

Bạn muốn viết một hàm (một hàm đệ quy là dễ nhất, nhưng có thể dễ dàng chạy ra khỏi không gian ngăn xếp trên các thư mục sâu) liệt kê các con của một thư mục. Nếu bạn tìm thấy một đứa trẻ đó là một thư mục, bạn recurse trên đó. Nếu không, bạn xóa các tập tin bên trong. Khi bạn hoàn thành, thư mục trống và bạn có thể xóa nó qua syscall.

Để liệt kê các thư mục trên Unix, bạn có thể sử dụng opendir, readdirclosedir. Để xóa bạn sử dụng rmdir() trên một thư mục trống (ví dụ: ở cuối chức năng của bạn, sau khi xóa các trẻ em) và unlink() trên một tệp. Lưu ý rằng trên nhiều hệ thống, thành viên d_type trong struct dirent không được hỗ trợ; trên các nền tảng này, bạn sẽ phải sử dụng stat()S_ISDIR(stat.st_mode) để xác định xem đường dẫn cụ thể có phải là một thư mục hay không.

Trên Windows, bạn sẽ sử dụng FindFirstFile()/FindNextFile() để liệt kê, RemoveDirectory() trên các thư mục trống và DeleteFile() để xóa tệp.

Dưới đây là một ví dụ mà có thể làm việc trên Unix (hoàn toàn chưa được kiểm tra):

int remove_directory(const char *path) 
{ 
    DIR *d = opendir(path); 
    size_t path_len = strlen(path); 
    int r = -1; 

    if (d) 
    { 
     struct dirent *p; 

     r = 0; 

     while (!r && (p=readdir(d))) 
     { 
      int r2 = -1; 
      char *buf; 
      size_t len; 

      /* Skip the names "." and ".." as we don't want to recurse on them. */ 
      if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) 
      { 
      continue; 
      } 

      len = path_len + strlen(p->d_name) + 2; 
      buf = malloc(len); 

      if (buf) 
      { 
      struct stat statbuf; 

      snprintf(buf, len, "%s/%s", path, p->d_name); 

      if (!stat(buf, &statbuf)) 
      { 
       if (S_ISDIR(statbuf.st_mode)) 
       { 
        r2 = remove_directory(buf); 
       } 
       else 
       { 
        r2 = unlink(buf); 
       } 
      } 

      free(buf); 
      } 

      r = r2; 
     } 

     closedir(d); 
    } 

    if (!r) 
    { 
     r = rmdir(path); 
    } 

    return r; 
} 
+0

câu trả lời hợp lý nhưng "dễ dàng chạy ra khỏi stackspace"? – peterchen

+0

@peterchen Có. Tôi đã thấy nó xảy ra. Nó cũng dễ dàng trên Windows hơn POSIX, vì 'WIN32_FIND_DATA' là rất lớn, trong khi' DIR * 'và' struct dirent * 'chỉ là hai con trỏ. – asveikau

+4

Lần đầu tiên tôi làm điều này, tôi đã không kiểm tra" .. " . Và có, kết quả là chương trình thay đổi thư mục tất cả các cách để c :, và sau đó bắt đầu xóa từ đó! "May mắn thay", nó đã xảy ra tại nơi làm việc. :) –

1

Bạn có thể sử dụng opendirreaddir để đọc mục thư mục và bỏ liên kết để xóa chúng.

0

unlink sẽ xóa tệp.

remove cũng sẽ xóa tệp nhưng di động hơn.

Bạn có thể thử system("rm -r ./path") nếu bạn đang làm việc trên Linux, người khác cũng có chức năng xóa đệ quy API Windows.

+30

'system()' luôn là câu trả lời sai. – asveikau

+5

Nó có sử dụng của nó, đó là một giải pháp nhanh chóng và bẩn. – Xorlev

+0

chức năng xóa đệ quy API Windows là gì? – Manuel

13

Cách dễ nhất để làm điều này là với remove_all chức năng của thư viện Boost.Filesystem. Bên cạnh đó, mã kết quả sẽ được di chuyển.

Nếu bạn muốn viết một cái gì đó cụ thể cho Unix (rmdir) hoặc cho Windows (RemoveDirectory) thì bạn sẽ phải viết một hàm xóa là đệ quy và thư mục con đệ quy.

EDIT

Hình như câu hỏi này là already asked, trên thực tế ai đó đã đề nghị remove_all Boost của. Vì vậy, xin vui lòng không upvote câu trả lời của tôi.

+2

brb tải xuống thư viện Boost.Filesystem trên virtualbox DOS của tôi để sử dụng trên trình biên dịch turbo c của tôi. – Dmitry

13

Nhiều hệ thống giống Unix (Linux, BSD và OS X, ít nhất) có các chức năng fts cho truyền tải thư mục. Để đệ quy xóa một thư mục, chỉ cần thực hiện một traversal chiều sâu đầu tiên (không có các liên kết sau) và xóa tất cả các tệp đã truy cập.

int recursive_delete(const char *dir) 
{ 
    int ret = 0; 
    FTS *ftsp = NULL; 
    FTSENT *curr; 

    // Cast needed (in C) because fts_open() takes a "char * const *", instead 
    // of a "const char * const *", which is only allowed in C++. fts_open() 
    // does not modify the argument. 
    char *files[] = { (char *) dir, NULL }; 

    // FTS_NOCHDIR - Avoid changing cwd, which could cause unexpected behavior 
    //    in multithreaded programs 
    // FTS_PHYSICAL - Don't follow symlinks. Prevents deletion of files outside 
    //    of the specified directory 
    // FTS_XDEV  - Don't cross filesystem boundaries 
    ftsp = fts_open(files, FTS_NOCHDIR | FTS_PHYSICAL | FTS_XDEV, NULL); 
    if (!ftsp) { 
     fprintf(stderr, "%s: fts_open failed: %s\n", dir, strerror(errno)); 
     ret = -1; 
     goto finish; 
    } 

    while ((curr = fts_read(ftsp))) { 
     switch (curr->fts_info) { 
     case FTS_NS: 
     case FTS_DNR: 
     case FTS_ERR: 
      fprintf(stderr, "%s: fts_read error: %s\n", 
        curr->fts_accpath, strerror(curr->fts_errno)); 
      break; 

     case FTS_DC: 
     case FTS_DOT: 
     case FTS_NSOK: 
      // Not reached unless FTS_LOGICAL, FTS_SEEDOT, or FTS_NOSTAT were 
      // passed to fts_open() 
      break; 

     case FTS_D: 
      // Do nothing. Need depth-first search, so directories are deleted 
      // in FTS_DP 
      break; 

     case FTS_DP: 
     case FTS_F: 
     case FTS_SL: 
     case FTS_SLNONE: 
     case FTS_DEFAULT: 
      if (remove(curr->fts_accpath) < 0) { 
       fprintf(stderr, "%s: Failed to remove: %s\n", 
         curr->fts_path, strerror(errno)); 
       ret = -1; 
      } 
      break; 
     } 
    } 

finish: 
    if (ftsp) { 
     fts_close(ftsp); 
    } 

    return ret; 
} 
+1

Mã ví dụ rất hay và giải thích - đây là câu trả lời được chấp nhận. –

+0

Giao diện 'fts' [không có trong musl libc] (http://wiki.musl-libc.org/wiki/FAQ#Q:_why_is_fts.h_not_included_.3F). –

0
//====================================================== 
// Recursely Delete files using: 
// Gnome-Glib & C++11 
//====================================================== 

#include <iostream> 
#include <string> 
#include <glib.h> 
#include <glib/gstdio.h> 

using namespace std; 

int DirDelete(const string& path) 
{ 
    const gchar* p; 
    GError* gerr; 
    GDir*  d; 
    int  r; 
    string ps; 
    string path_i; 
    cout << "open:" << path << "\n"; 
    d  = g_dir_open(path.c_str(), 0, &gerr); 
    r  = -1; 

    if (d) { 
     r = 0; 

     while (!r && (p=g_dir_read_name(d))) { 
      ps = string{p}; 
      if (ps == "." || ps == "..") { 
      continue; 
      } 

      path_i = path + string{"/"} + p; 


      if (g_file_test(path_i.c_str(), G_FILE_TEST_IS_DIR) != 0) { 
      cout << "recurse:" << path_i << "\n"; 
      r = DirDelete(path_i); 
      } 
      else { 
      cout << "unlink:" << path_i << "\n"; 
      r = g_unlink(path_i.c_str()); 
      } 
     } 

     g_dir_close(d); 
    } 

    if (r == 0) { 
     r = g_rmdir(path.c_str()); 
    cout << "rmdir:" << path << "\n"; 

    } 

    return r; 
} 
+0

Bao quanh mã của bạn với một lời giải thích sẽ cải thiện nghiêm túc câu trả lời của bạn. – zx485

7

Nếu bạn đang sử dụng một hệ điều hành POSIX tuân thủ, bạn có thể sử dụng nftw() cho duyệt cây tập tin và loại bỏ (loại bỏ các tập tin hoặc thư mục). Nếu bạn đang ở trong C++ và dự án của bạn sử dụng boost, nó không phải là một ý tưởng tồi để sử dụng Boost.Filesystem như được đề xuất bởi Manuel.

Trong ví dụ code dưới đây tôi quyết định không đi qua liên kết tượng trưng và gắn kết điểm (chỉ để tránh bị xóa lớn :)):

#include <stdio.h> 
#include <stdlib.h> 
#include <ftw.h> 

static int rmFiles(const char *pathname, const struct stat *sbuf, int type, struct FTW *ftwb) 
{ 
    if(remove(pathname) < 0) 
    { 
     perror("ERROR: remove"); 
     return -1; 
    } 
} 

int main(int argc, char *argv[]) 
{ 
    if (argc != 2) 
    { 
     fprintf(stderr,"usage: %s path\n",argv[0]); 
     exit(1); 
    } 

    // Delete the directory and its contents by traversing the tree in reverse order, without crossing mount boundaries and symbolic links 

    if (nftw(argv[1], rmFiles,10, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) < 0) 
    { 
     perror("ERROR: ntfw"); 
     exit(1); 
    } 

    return 0; 
} 
+0

Tôi rất vui vì ai đó đã đề cập đến 'ntfw'. :) –

Các vấn đề liên quan