淮北集团网站建设,公司flash网站模板,网站程序设置主页面,新手做淘宝客网站教程IO编程的本质是通过 API 操作 文件。
什么是 IO
I - Input 输入O - Output 输出
这里的输入和输出都是站在应用#xff08;运行中的程序#xff09;的角度。外部特指文件。
这里的文件是泛指#xff0c;并不是只表示存在存盘中的常规文件。还有设备、套接字、管道、链接…IO编程的本质是通过 API 操作 文件。
什么是 IO
I - Input 输入O - Output 输出
这里的输入和输出都是站在应用运行中的程序的角度。外部特指文件。
这里的文件是泛指并不是只表示存在存盘中的常规文件。还有设备、套接字、管道、链接等等。在 Linux 系统中 “一切皆文件”目的是为了统一接口简化编程。简单点说 输入/输出编程 :让你将输入/输出功能 作用在 文件 上 ----文件(7种) --------------------- 对文件进行 IO 操作 ----将某些代码数据 保留在 文件 上 好处: 1 将某些代码数据 保留在 文件 上 ----- 关于这一点请查阅文章《将数据保留文件持久化》 2 丰富你访问底层的手段 3 可以通过代码打开一些特殊文件 (管道/套接字/字符设备等等) 文件是什么 文件操作系统中一种二进制/相关数据有序的集合文件名这个数据集合的名称Linux---有哪些文件类型? 共计为 7大类- 普通文件:C程序/可执行文件d 目录 --- 文件夹c 字符设备 --- 驱动使用b 块设备 --- 驱动使用s 套接字 --- 网络编程使用p 管道 --- 多进程线程使用l 软链接 --- 快捷方式标准 IO 和系统 IO 这里展示了三种内核访问方式Shell 命令访问内核、系统 API 访问内核 和 C 库函数访问内核。
1. Shell 命令访问内核
Shell 是操作系统的命令行接口用户通过输入命令如 ls、cat、cp 等间接与内核交互。Shell 命令通过调用操作系统提供的系统 API与内核交互完成任务。例如ls 命令通过调用系统 API 获取目录列表。
工作流程结合图示
用户输入 Shell 命令如 ls。Shell 将命令解释为系统调用例如 open()、read() 等。系统调用接口API将请求传递给操作系统内核。内核通过驱动程序访问硬件设备如磁盘获取数据。内核将数据返回给 ShellShell 将结果显示给用户。
适合直接操作文件或目录用户无需编程即可操作内核高层次封装主要适合简单的文件管理操作例如查看文件、复制文件等。
2. 系统 API 访问内核
系统 API如 open()、read()、write()是操作系统提供的接口用于程序直接与内核交互。程序员通过调用这些 API可以访问文件系统、硬件设备等底层资源。
工作流程结合图示
应用程序调用系统 API例如 open() 打开文件、read() 读取文件内容、write() 写入文件。系统 API 调用操作系统的内核功能完成对设备或文件的操作。内核通过驱动程序与硬件设备交互如读取磁盘数据。操作系统将结果返回给应用程序。
优势尤其明显直接访问内核开发者通过系统 API 与内核交互并且提供了高效的文件操作能力适合对性能要求较高的场景比 Shell 命令更加灵活但需要更丰富编程知识。
3. C 库函数访问内核标准 I/O
C 标准库如 stdio.h 提供的函数 fopen()、fclose()、fwrite() 等对系统 API 进行了封装简化了文件操作。应用程序通过调用 C 库函数间接访问内核。例如fopen() 实际上会调用系统 API open()。
工作流程结合图示
应用程序调用 C 标准库函数如 fopen()。标准库函数将调用转换为系统 API 调用如从 fopen() 转换为 open()。系统 API 通过内核与硬件设备交互如文件读取、写入。内核将结果返回给标准库函数应用程序通过标准库函数获取结果。
C 库函数访问内核实现了更高层次的封装C 库函数将系统调用封装为易用的接口简化了开发具备跨平台性C 标准库屏蔽了操作系统差异程序更容易移植适合一般开发更方便、易于维护但性能可能略低于直接使用系统 API。
Shell 命令层 用户通过命令如 ls访问内核。图中未直接显示 Shell 命令路径但 Shell 命令最终通过系统 API 调用内核。 系统 API 层 图中展示了系统 API如 open()、read()、close() 等。应用程序直接调用这些 API与内核交互。 C 库函数层 标准 C 库如 fopen()封装了底层 API 调用提供了易用的接口。图中显示了 C 库函数调用系统 API 的过程如 fopen() 调用 open()。 内核和设备驱动层 如图所示内核通过驱动程序与硬件设备交互的过程如文件存储在磁盘上通过驱动读取数据。
不同访问方式在代码上的差异
Shell 命令访问 通过 Shell 命令直接操作文件无需编写程序。用户通过命令行与内核交互。
示例任务是读取文件内容并将其打印到屏幕。
# 创建一个文件并写入内容
echo Hello, this is a test file. test.txt# 通过 Shell 命令读取文件内容并打印
cat test.txt输出
Hello, this is a test file.
# 优点简单、直接无需编程。
# 缺点灵活性差无法嵌入复杂的逻辑。系统 API 访问 通过操作系统提供的系统调用如 open()、read()直接访问内核。
示例使用 C 语言中的系统调用接口读取文件内容。
#include fcntl.h
#include unistd.h
#include stdio.hint main() {// 打开文件int fd open(test.txt, O_RDONLY);if (fd 0) {perror(Error opening file);return 1;}// 读取文件内容char buffer[1024];ssize_t bytes_read read(fd, buffer, sizeof(buffer) - 1);if (bytes_read 0) {perror(Error reading file);close(fd);return 1;}// 确保字符串以 \0 结尾buffer[bytes_read] \0;// 打印文件内容printf(File content:\n%s\n, buffer);// 关闭文件close(fd);return 0;
}输出
File content:
Hello, this is a test file.# 优点
# 提供对文件操作的精细控制。
# 性能高适合对系统资源的直接访问。
# 缺点
# 开发复杂度较高需要手动管理资源如文件描述符的关闭等。C 库函数访问 通过 C 标准库函数如 fopen()、fgets()封装系统调用简化文件操作。
示例使用 C 标准库函数实现文件读取。
#include stdio.hint main() {// 打开文件FILE *file fopen(test.txt, r);if (file NULL) {perror(Error opening file);return 1;}// 读取文件内容并打印char buffer[1024];while (fgets(buffer, sizeof(buffer), file) ! NULL) {printf(%s, buffer);}// 关闭文件fclose(file);return 0;
}输出
Hello, this is a test file.# 优点
# 使用方便屏蔽了底层系统调用的细节。
# 提供了一些高级功能如缓冲。
# 缺点
# 性能略低于直接调用系统 API。访问方式代码复杂度性能应用场景Shell 命令访问低较低简单的文件操作任务如查看、编辑文件内容系统 API 访问高高直接访问内核性能要求高的场景如大型文件读写或底层系统编程C 库函数访问中中有缓冲优化通用场景如日志文件处理、常规文件读写
复杂场景三者的差别 任务将文件内容逐行读取并将每行的长度打印出来。
Shell 命令实现
while read line; doecho Length: ${#line}
done test.txt系统 API 实现
#include fcntl.h
#include unistd.h
#include stdio.h
#include string.hint main() {int fd open(test.txt, O_RDONLY);if (fd 0) {perror(Error opening file);return 1;}char buffer[1024];ssize_t bytes_read;while ((bytes_read read(fd, buffer, sizeof(buffer) - 1)) 0) {buffer[bytes_read] \0;char *line strtok(buffer, \n);while (line ! NULL) {printf(Length: %ld\n, strlen(line));line strtok(NULL, \n);}}close(fd);return 0;
}C 库函数实现
#include stdio.h
#include string.hint main() {FILE *file fopen(test.txt, r);if (file NULL) {perror(Error opening file);return 1;}char buffer[1024];while (fgets(buffer, sizeof(buffer), file) ! NULL) {buffer[strcspn(buffer, \n)] \0; // 去掉换行符printf(Length: %ld\n, strlen(buffer));}fclose(file);return 0;
}在实际开发中根据任务复杂度和性能需求选择合适的访问方式即可。例如
简单任务用 Shell 命令。高性能需求用系统 API。通用场景用 C 标准库函数。
系统调用(文件IO)
省流版简单理解文件IO更贴切底层有系统地方就有文件IO 用户空间进程访问内核的接口 把用户从底层的硬件编程中解放出来 极大的提高了系统的安全性 使用户程序具有可移植性 是操作系统的一部分 系统调用接口是内核的组成部分不管你是否调用这些接口它都存在于内核中。调用它时不需要加载直接跳转执行。
库函数(标准IO)
省流版简单理解标准IO更依赖封装的C库函数库应用面相对没有文件IO 库函数为了实现某个功能而封装起来的API集合提供统一的编程接口更加便于应用程序的移植是语言或者应用程序的一部库函数是应用的一部分调用它时需要加载到进行中然后才跳转执行程序结束时会卸载。
访问区别
1 文件指针 --- FILE * ---文件流/流指针FILE --- 是一个结构体别名FILE利用拥有的成员都属于系统底层成员//stdio.htypedef struct _iobuf{char* _ptr; //文件输入的下一个位置int _cnt; //当前缓冲区的相对位置char* _base; //文件初始位置int _flag; //文件标志 int _file; //文件有效性 ------**** 文件管理块 FCBint _charbuf; //缓冲区是否可读取int _bufsiz; //缓冲区字节数char* _tmpfname; //临时文件名} FILE;2 文件描述符 ----- *:贯穿了整个应用层顺序分配的非负整数内核用以标识一个特定进程正在访问的文件其他资源(socket、pipe等)的访问标识系统调用系统IO使用 文件描述符 来唯一标识进程所打开的文件包含常规文件、目录、块设备文件、字符设备文件、管道、符号链接、套接字等。FILE 流
使用非负整数表示012…类型为 int。 每个 shell进程默认会打开三个文件描述符标准输入/标准输出/标准错误输出
STDIN_FILENO - 0 - 标准输入STDOUT_FILENO - 1- 标准输出STDERR_FILENO - 2 - 标准出错
以上三个文件描述符在进程中可以直接使用无须额外打开。另外这三个标准文件很特殊 — 既是已存在的文件也是文件指针同时还是文件描述符。
每个 shell进程默认打开的三个文件描述符所对应的 FILE 流文件指针 文件描述符标准输入 stdin 0标准输出 stdout 1 标准错误输出 stderr 2在 /usr/include/stdio.h 头文件中声明了以下全局流/* Standard streams. */extern struct _IO_FILE *stdin; /* Standard input stream. */extern struct _IO_FILE *stdout; /* Standard output stream. */extern struct _IO_FILE *stderr; /* Standard error output stream. *//* C89/C99 say theyre macros. Make them happy. */#define stdin stdin#define stdout stdout#define stderr stderr其他情况下文件指针 和 文件描述符 操作 则是完全独立的。
文件指针标准IO文件描述符文件IO文件I/O — 不用缓存的I/O 通过文件描述符进行访问open()/read()/write()/lseek()/close()… 标准I/O 通过 FILE* 进行访问printf()/fprintf()/fopen()/fread()/fwrite()/fseek()/fclose()…
出错处理
/usr/include/errno.h 中定义了错误代码。
#include errno.h真正定义这些错误代码的文件是/usr/include/asm-generic/errno-base.h
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _ASM_GENERIC_ERRNO_BASE_H
#define _ASM_GENERIC_ERRNO_BASE_H#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */#endif另外还有一个文件/usr/include/asm-generic/errno.h
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _ASM_GENERIC_ERRNO_H
#define _ASM_GENERIC_ERRNO_H#include asm-generic/errno-base.h#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available *//** This error code is special: arch syscall entry code will return* -ENOSYS if users try to call a syscall that doesnt exist. To keep* failures of syscalls that really do exist distinguishable from* failures due to attempts to use a nonexistent syscall, syscall* implementations should refrain from returning -ENOSYS.*/
#define ENOSYS 38 /* Invalid system call number */#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */#define EDEADLOCK EDEADLK#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define ENOPROTOOPT 92 /* Protocol not available */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#define ECANCELED 125 /* Operation Canceled */
#define ENOKEY 126 /* Required key not available */
#define EKEYEXPIRED 127 /* Key has expired */
#define EKEYREVOKED 128 /* Key has been revoked */
#define EKEYREJECTED 129 /* Key was rejected by service *//* for robust mutexes */
#define EOWNERDEAD 130 /* Owner died */
#define ENOTRECOVERABLE 131 /* State not recoverable */#define ERFKILL 132 /* Operation not possible due to RF-kill */#define EHWPOISON 133 /* Memory page has hardware error */#endif全局错误码errno 在errno.h中定义全局可见错误值定义为“EXXX”形式如EACCESS想阅读全局错误码: 1 /usr/include/asm-generic/errno-base.h 2 /usr/include/asm-generic/errno.h 处理规则如果没有出错则 errno 值不会被一个例程清除即只有出错时才需要检查 errno 值任何函数都不会将 errno 值设置为 0errno.h 中定义了所有常数都不为 0错误信息输出strerror() - 映射errno对应的错误信息 --- 有BUG有的人Linux能用有的人不能用而且只会告诉你错了什么但不会告诉你具体哪里错了。perror() – 输出用户信息及errno对应的错误信息 if(错误返回){perror(自定义错误标志);return;
}
例如:
int tempscanf(%d,a); //一定要注意:scanf的错误返回你一定要知道
if(temp0){perror(嘿嘿此处报错咯~);
}strerror 函数
#include string.h
char *strerror(int errnum);// 将 errnum 翻译为对应错误的解释字符串并返回字符串指针
// 当传递无效错误号 nnn 时返回 Unknown error nnnperror 函数
#include stdio.h
void perror(const char *s);// 将 s 后加一个 : 号加空格即 : 并且将 errno 对应的描述字符串连接在后面打印输出示例代码
#include errno.h
#include string.h
#include stdio.hint main(void)
{FILE *fp;// 打印 EINVAL 错误号对应的错误描述printf(EINVAL - %s\n, strerror(EINVAL));// 打印无效的错误号 150 对应的描述printf(150 - %s\n, strerror(150));// 以只读的方式打开 ./abc.txt如果文件不存在则会打开失败fp fopen(./abc.txt, r);// 直接打印当前 errno 的值所对应的描述printf(errno %d, %s\n, errno, strerror(errno));if (!fp) {// 打印错误描述常用perror(打开文件 ./abc.txt 失败);return -1;}// 关闭文件流fclose(fp);return 0;
}以上。仅供学习与分享交流请勿用于商业用途转载需提前说明。
我是一个十分热爱技术的程序员希望这篇文章能够对您有帮助也希望认识更多热爱程序开发的小伙伴。 感谢