文章目錄
一.目錄操作
1.獲取、改變、創建、刪除當前目錄
- char* getcwd(char*, size_t)
- int chdir(char*, mode_t)
創建和刪除目錄
- int mkdir(char*, mode_t)
- int rmdir(char*)
void test1()
{
cout << "Now working directory is :" << endl;
cout << getcwd(NULL, 0) << endl;
if (mkdir("./newdir", 0775))
cout << "mkdir ERROR" << endl;
if (chdir("./newdir/"))
cout << "can't find the directory" << endl;
cout << getcwd(NULL, 0) << endl;
if (chdir(".."))
cout << "can't find the directory" << endl;
if (rmdir("newdir"))
cout << "rmdir ERROR" << endl;
}
2.打開目錄流、讀取目錄流、關閉目錄流
- DIR* opendir(char*)
- struct dirent* readdir(char*)
- int closedir(DIR*)
整個與FILE*的文件流十分相似,也很好理解。
struct dirent結構體用於存儲目錄下讀取到的文件信息。
通過下面的操作,可以將newdir目錄下的文件全部讀取出來。
void test2()
{
DIR *dir = opendir("newdir");
if (!dir)
cout << "opendir ERROR" << endl;
struct dirent *dir_info;
while (dir_info = readdir(dir))
cout << dir_info->d_name << endl;
closedir(dir);
}
3.讀取文件的類型,大小, 最近訪問時間等
- int stat(const char*, struct stat*)
- int fstat(int fd, struct stat*)
struct stat 中最常用的兩個字段:
- st_mode 文件類型
- st_size 文件大小
針對st_mode的判斷有以下幾種:
- S_ISREG(st_mode) 是否爲普通文件
- S_ISDIR(st_mode) 是否爲目錄
void test3()
{
struct stat stat_info;
cout << getcwd(NULL, 0) << endl;
if (stat("newdir", &stat_info))
cout << "stat ERROR" << endl;
if (S_ISREG(stat_info.st_mode))
cout << "file" << endl;
else if (S_ISDIR(stat_info.st_mode))
cout << "dir" << endl;
cout << stat_info.st_size << endl;
cout << stat_info.st_uid << endl;
cout << stat_info.st_gid << endl;
cout << "輸出文件的最近依次的訪問時間:" << endl;
//MM DD HH:mm
time_t rawtime = stat_info.st_atime;
struct tm *timeinfo = localtime(&rawtime);
if (timeinfo->tm_min > 9)
cout << timeinfo->tm_mon + 1 << "月 " << timeinfo->tm_mday << "日 " << timeinfo->tm_hour << ":" << timeinfo->tm_min << endl;
else
cout << timeinfo->tm_mon + 1 << "月 " << timeinfo->tm_mday << "日 " << timeinfo->tm_hour << ":0" << timeinfo->tm_min << endl;
}
4.綜合練習:實現 tree 命令
以樹形結構輸出該目錄下的文件
採用DFS的方法輸出
void tree(const char *dirname, int depth)
{
DIR *dir = opendir(dirname);
if (!dir)
return;
chdir(dirname);
struct dirent *dirbuf;
while (dirbuf = readdir(dir))
{
if (!strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))
continue;
else
{
cout << "|" << setw(depth) << setfill(' ') << "--" << dirbuf->d_name << endl;
tree(dirbuf->d_name, depth + 5);
}
}
chdir("..");
closedir(dir);
}
void test4()
{
tree("newdir", 0);
}
系統tree輸出:
wwx@VM-0-7-ubuntu:~/Linux/Day04/fileSystem/newdir$ tree
.
|-- dir1
| `-- dir1file
|-- dir2
| `-- dir2file
|-- file1
`-- file2
2 directories, 4 files
程序輸出:
wwx@VM-0-7-ubuntu:~/Linux/Day04/fileSystem$ cd "/home/wwx/Linux/Day04/fileSystem/" && g++ main1.cpp -o main1 && "/home/wwx/Linux/Day04/fileSystem/"main1
|--dir1
| --dir1file
|--file1
|--file2
|--dir2
| --dir2file
二.文件操作
在linux環境下,一般來操作文件都是通過操作文件描述符(文件句柄)來進行操作。
1.打開關閉文件
- int open(const char*, int , mode_t)
- int close(int)
2.讀取,寫入文件
- size_t read(int fd, char* buf, size_t size)
- size_t write(int fd, char* buf, size_t size)
練習:從file1中讀取, 再寫到file2中
void test1()
{
int fd1 = open("file1", O_RDWR | O_CREAT, 0755);
int fd2 = open("file2", O_RDWR | O_CREAT, 0755);
if (fd1 == -1)
cout << "fd1 open ERROR" << endl;
if (fd2 == -1)
cout << "fd2 open ERROR" << endl;
char buf[1024] = {0};
int len = 0;
while ((len = read(fd1, buf, sizeof(buf))) > 0)
{
cout << len << endl;
write(fd2, buf, len);
memset(buf, 0, sizeof(buf));
}
close(fd1);
close(fd2);
}
3. 改變文件大小
- int ftruncate(int fd, off_t length)
將文件從length偏移的字節數開始截斷
void test3()
{
int fd = open("file1", O_RDWR);
ftruncate(fd, 1000);
close(fd);
}
4.文件定位 與 文件空洞設計
- off_t lseek(int fd, off_t offset, int whence)
whence:
- SEEK_SET
- SEEK_CUR
- SEEK_END
文件空洞設計一般用於共享內存
//文件空洞設計
void test4()
{
int fd = open("file3", O_RDWR | O_CREAT, 0755);
lseek(fd, 1024, SEEK_SET);
write(fd, "HelloWorld", strlen("HelloWorld"));
close(fd);
}
5.文件描述符的複製
文件描述符類比智能指針的引用計數,也可以理解成深拷貝
-
int dup(int oldfd)
此種方式是自動分配文件描述符(從小到大)
當使用 int fd2 = fd; 語句時, 如果進行 close(fd), 那麼fd, fd2指向的文件會立刻關閉
當使用 int fd2 = dup(fd); 語句時, 如果進行了 close(fd), fd2指向的文件因爲引用計數仍爲1,所以文件不會關閉 -
int dup2(int oldfd, int newfd)
此種方式是自己定義新的文件描述符(newfd)
void test5()
{
int fd = open("file4", O_RDWR | O_CREAT, 0755);
cout << "fd:" << fd << endl;
// int fd2 = fd;
int fd2 = dup(fd);
cout << "fd2:" << fd2 << endl;
close(fd);
char buf[1024];
read(fd2, buf, sizeof(buf));
cout << buf << endl;
}
6.標準輸入、輸出、錯誤輸出
分別代表文件描述符中的0、1、2
關閉文件描述符 1 之後,fd2分配到的就是輸出 1 , 那麼無論我們輸出什麼到輸出流中,都不會在屏幕中的顯示,而是寫在fd2指向的文件中
void test6()
{
int fd = open("file6", O_RDWR|O_CREAT, 0755);
cout << "fd:" << fd << endl;
close(1);//關閉輸出
int fd2 = dup(fd);
cout << "fd2:" << fd2 << endl;
cout << "HelloWorld" << endl;
close(fd);
}