【Linux基础】文件IO

女爷i 2023-10-17 02:50 57阅读 0赞

说明

参考:《UNIX环境高级编程》中文版第三版

编程环境:OS X 10.11.5 Xcode 7.3.1

文件I/O

下面介绍各类文件I/O操作。

  1. #include <fcntl.h>
  2. int open(const char * path, int oflag, ...);
  3. int openat(int fd, const char * path, int oflag, ...);

用于打开或者创建文件(创建文件时需要注意flag必须有O_CREAT这个选项,并指定访问权限(通过后面的不定参数)),成功返回文件描述符,它是一个非负整数,失败返回-1。

path是需要打开或者创建的文件的名字。如果path是绝对路径,open()和openat()没有区别,openat()中的fd参数无效。如果path是相对路径,对于openat(),fd参数指定了起始路径,fd也是个文件描述符,它通过打开相对路径所在的目录来获得;对于open(),则指定当前目录为起始路径。

oflag是一系列的选项,确定打开方式,如只读、只写、读写等等:

  1. #define O_ACCMODE 0003
  2. #define O_RDONLY 00
  3. #define O_WRONLY 01
  4. #define O_RDWR 02
  5. #define O_CREAT 0100 /* not fcntl */
  6. #define O_EXCL 0200 /* not fcntl */
  7. #define O_NOCTTY 0400 /* not fcntl */
  8. #define O_TRUNC 01000 /* not fcntl */
  9. #define O_APPEND 02000
  10. #define O_NONBLOCK 04000
  11. #define O_NDELAY O_NONBLOCK
  12. #define O_SYNC 010000
  13. #define FASYNC 020000 /* fcntl, for BSD compatibility */
  14. #define O_DIRECT 040000 /* direct disk access hint */
  15. #define O_LARGEFILE 0100000
  16. #define O_DIRECTORY 0200000 /* must be a directory */
  17. #define O_NOFOLLOW 0400000 /* don't follow links */
  18. #define O_NOATIME 01000000

下面是一个例子:

  1. #include <stdio.h>
  2. #include <fcntl.h>
  3. #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
  4. int main()
  5. {
  6. int fd = 0;
  7. if( (fd = open("open_test", O_RDWR | O_CREAT, FILE_MODE)) != -1 )
  8. {
  9. printf("open file fd: %d\n", fd);
  10. }
  11. else
  12. {
  13. printf("open file failed\n");
  14. }
  15. return 0;
  16. }

执行结果:

  1. open file fd: 3
  2. Program ended with exit code: 0

上例中创建文件的方式可以用另外一个函数来代替:

  1. #include <fcntl.h>
  2. int creat(const char * path, mode_t mode);

成功时返回文件描述符,失败时返回-1。它相当于:

  1. open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);

关于mode_t,它表示的是文件的访问权限,有如下的值:

  1. /* File mode */
  2. /* Read, write, execute/search by owner */
  3. #define S_IRWXU 0000700 /* [XSI] RWX mask for owner */
  4. #define S_IRUSR 0000400 /* [XSI] R for owner */
  5. #define S_IWUSR 0000200 /* [XSI] W for owner */
  6. #define S_IXUSR 0000100 /* [XSI] X for owner */
  7. /* Read, write, execute/search by group */
  8. #define S_IRWXG 0000070 /* [XSI] RWX mask for group */
  9. #define S_IRGRP 0000040 /* [XSI] R for group */
  10. #define S_IWGRP 0000020 /* [XSI] W for group */
  11. #define S_IXGRP 0000010 /* [XSI] X for group */
  12. /* Read, write, execute/search by others */
  13. #define S_IRWXO 0000007 /* [XSI] RWX mask for other */
  14. #define S_IROTH 0000004 /* [XSI] R for other */
  15. #define S_IWOTH 0000002 /* [XSI] W for other */
  16. #define S_IXOTH 0000001 /* [XSI] X for other */

关闭文件使用的函数:

  1. #include <unistd.h>
  2. int close(int fd);

需要注意使用了不同的头文件。成功时返回0,出错时返回-1。

  1. #include <unistd.h>
  2. off_t lseek(int fd, off_t offset, int whence);

lseek()显式地为一个打开文件设置偏移量。

通常,读写操作都从当前文件偏移量开始。

默认情况下,当打开一个文件时,除非指定了O_APPEND选项,否则该偏移量被设置为0。

fd表示文件描述符,对应特定的文件。

offset和whence配合使用:

1)whence是SEEK_SET时,设置偏移量为从文件开始处offset个字节;

2)whence是SEEK_CUR时,设置偏移量为从文件当前偏移位置开始处offset个字节,offset可正可负;

3)whence是SEEK_END时,设置偏移量为文件长度加offset个字节,offset可正可负。

成功时,返回新的文件偏移量;出错时返回-1。

下面是获取当前文件偏移量的一个方法:

  1. off_t offset = lseek(fd, 0, SEEK_CUR);
  2. printf("offset : %lld\n", offset);

注意,lseek只负责记录文件偏移量,并不会引起任何的I/O操作。

下面两个函数才是具体的I/O操作:

  1. #include <unistd.h>
  2. ssize_t read(int fd, void *buf, size_t nbytes);
  3. ssize_t write(int fd, const void *buf, size_t nbytes);

read()成功返回读到的字节,它小于等于nbytes;失败返回-1。

write()成功返回写入的字节;失败返回-1。

一个完整的示例:

  1. #include <stdio.h>
  2. #include <fcntl.h>
  3. #include <unistd.h>
  4. #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
  5. int main()
  6. {
  7. int fd;
  8. off_t offset;
  9. char *tmp = "hello world";
  10. char s[20] = {0};
  11. if( (fd = open("open_test", O_RDWR | O_CREAT, FILE_MODE)) != -1 )
  12. {
  13. printf("open file fd: %d\n", fd);
  14. }
  15. else
  16. {
  17. printf("open file failed\n");
  18. return 1;
  19. }
  20. offset = lseek(fd, 0, SEEK_CUR);
  21. printf("offset : %lld\n", offset);
  22. if( 12 == write(fd, tmp, 12))
  23. {
  24. printf("write file success\n");
  25. }
  26. if ( (0 == lseek(fd, 0, SEEK_SET)) && (read(fd, &s, 100) != -1) )
  27. {
  28. printf("read from file: %s\n", s);
  29. }
  30. close(fd);
  31. return 0;
  32. }

结果:

  1. open file fd: 3
  2. offset : 0
  3. write file success
  4. read from file: hello world
  5. Program ended with exit code: 0
  6. #include <unistd.h>
  7. int dup(int fd);
  8. int dup2(int fd, int fd2);

复制一个现有的文件描述符。成功则返回新的文件描述符,失败则返回-1。

对于dup2(),如果fd2已经打开,则先关闭;如果fd等于fd2,则dup2()返回fd2,而不是关闭它。

下面的例子复制了标准输出,之后再使用write写文件的话,相当于写到了标准输出上:

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. int main()
  4. {
  5. int tmp = dup(STDOUT_FILENO);
  6. write(tmp, "Hello world\n", 12);
  7. return 0;
  8. }
  9. #include <fcntl.h>
  10. int fcntl(int fd, int cmd, ...);

用于改变已经打开的文件的属性。

根据cmd的不同,fcntl()函数有不同的功能:

1)复制已有的文件描述符,功能同dup、dup2;

2)获取/设置文件描述符标志;

3)获取/设置文件状态标志;

4)获取/设置异步I/O所有权;

5)获取/设置记录锁。

  1. #include <unistd.h>
  2. #include <sys/ioctl.h>
  3. int ioctl(int fd, int request, ...);

这个函数包含其他函数无法应用到的I/O操作。这里不特别介绍了。

发表评论

表情:
评论列表 (有 0 条评论,57人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Linux文件IO

    目录 【1】文件系统重点概念 【2】重谈C语言的文件操作 【2.1】向文件写入数据 【2.2】向文件读取数据 【2.3】向文件追加数据 【3】系统文件IO 【3.