
首先linux中所有的操作都是基于文件操作实现的这是基准。1.编写程序过程中的注意事项1.关于goto关键字的说法在应用层中goto关键字是不提倡使用的它会是逻辑混乱不好调试与梳理逻辑结构但是在驱动中goto是很常见的关于这个关键字使用的侧重点是他会统一的释放资源。在linux驱动中会按照一定的顺序申请资源如果有一步申请失败或者是操作失败会在函数的尾部统一释放资源应用层与驱动层的侧重点不同。2.在Linux中关于涉及到资源的这一部分每次都要考虑到操作失败与资源申请失败的情况。3.关于函数的linux部分的函数调用可以查看man手册。2.文件操作部分首先要区分系统调用与库调用要搞清楚的是系统调用是内核提供给应用层的也就是系统调用一端连接的是内核部分实现的文件操作另外一段连接的是应用层操作。库函数对文件的操作是基于系统调用之上的库函数的存在是为了兼容不同的操作系统给用户一个统一的接口其次对于linux而言库函一般是带有缓冲的减少从用户态到内核态的切换次数。1.系统调用函数文件io系统调用的函数 open(test.txt, O_RDWR | O_CREAT, 0644); write(fd, aaaaaa, 6);open(test2.txt, O_RDWR | O_CREAT, 0644);read(fd, buf, 1024);write(fd2, buf, 6);系统调用对文件的操作都是基于文件描述符进行操作的fd,fd,其中的文件描述符也是一种资源有数量限制使用ulimit-n命令可以查看自已申请分配的文件描述符一般都是从3开始的0标准输入1标准输出2标准错误。可以使用strerror、perror这两个函数来打印出函数的错误信息。使用O_APPEND打开文件时使用lseek不能改变写的位置偏移量并且读的位置偏移量还是开头部分。当读取文件时O_APPEND标志并不会影响读位置偏移量即使使用了 O_APPEND标志读文件位置偏移量默认情况下依然是文件头一个进程内多次 open 打开同一个文件在内存中并不会存在多份动态文件一个进程内多次open打开同一个文件不同文件描述符所对应的读写位置偏移量是相互独立的复制得到的文件描述符与原文件描述符都指向同一个文件表所以它们的文件读写偏移量是一样的可以在不使用O_APPEND标志的情况下通过文件描述符复制来实现接续写。2.标准io(c标准库)1.文件io是基于文件描述符来操作的标准io是基于file*指针进行操作的FILE 是一个结构体数据类型它包含了标准I/O库函数为管理文件所需要的所有信息包括用于实际 I/O 的文件描述符、指向文件缓冲区的指针、缓冲区的长度、当前缓冲区中的字节数以及出错标志等。FILE 数据结构定义在标准 I/O库函数头文件stdio.h中。fopen(./test_file,w)因为fread();的返回值无法判断是读取完成还是读取错误等小于要读取的个数时需要使用ferror()函数来判断是不是读取错误。feof(file)用于判断是否读取到文件尾。库函数 ferror()用于测试参数stream所指文件的错误标志如果错误标志被设置了则调用ferror()函数 将返回一个非零值如果错误标志没有被设置则返回 0库函数 clearerr()用于清除end-of-file标志和错误标志当调用feof()或ferror()校验这些标志后通常需要清除这些标志避免下次校验时使用到的是上一次设置的值此时可以手动调用 clearerr()函数清除标志。2. 关于printf()、fprintf()、dprintf()、sprintf()、snprintf()的区别printf()函数用于将格式化数据写入到标准输出dprintf()和fprintf()函数用于将格式化数据写入到指定的 文件中两者不同之处在于fprintf()使用FILE指针指定对应的文件、而dprintf()则使用文件描述符fd指定 对应的文件sprintf()、snprintf()函数可将格式化的数据存储在用户指定的缓冲区buf中。关于scanf(),fscanf(), sscanf(),区别scanf()将用户输入标准输入的数据进行格式化转换并进行存储,fscanf()函数从指定文件中读取数据作为格式转换的输入数据文件通过FILE 指针指定,sscanf()将从参数str所指向的字符串缓冲区中读取数据作为格式转换的输入数据.3.io缓冲部分1.文件io缓冲部分read()和 write()系统调用在进行文件读写操作的时候并不会直接访问磁盘设备而是仅仅在用户空间缓冲区和内核缓冲区kernel buffer cache之间复制数据内核稍后会将数据写入到磁盘设备中具体是什么时间点写入到磁盘这个其实是不确定的由内核根据相应的存储算法自动判断。也可以使用fsync()、fdatasync()、sync()手动刷新到磁盘中fsync()将参数fd 所指文件的内容数据和元数据写入磁盘,fdatasync()仅将参数fd 所指文件的内容数据写入磁 盘并不包括文件的元数据sync()会将所有文件I/O 内核缓冲区中的文件内容数据和元数据全部更新到磁盘设备中.也可以在open文件时加入参数O_DIRECT其有一些限制不过这个一般不会用到2.标准io缓冲部分虽然标准io是对文件io的进一步封装但在效率、性能上标准 I/O要优于文件I/O其原因在于标准I/O实现维护了自己的缓冲区我们把这个缓冲区称为 stdio 缓冲区。C 语言提供了一些库函数可用于对标准I/O的stdio缓冲区进行相关的一些设置包括setbuf()、setbuffer() 以及 setvbuf()int setvbuf(FILE *stream, char *buf, int mode, size_t size);其参数解释streamFILE指针用于指定对应的文件每一个文件都可以设置它对应的stdio 缓冲区。buf如果参数buf不为NULL那么buf指向size大小的内存区域将作为该文件的stdio 缓冲区如果 buf等 于 NULL那么stdio库会自动分配一块空间作为该文件的stdio缓冲区除非参数mode 配置为非缓冲模 式。mode参数mode用于指定缓冲区的缓冲类型可取值如下1._IONBF不对I/O进行缓冲无缓冲。意味着每个标准I/O函数将立即调用write()或者read()并且忽略 buf和size参数可以分别指定两个参数为NULL和0。标准错误stderr默认属于这一种类型从而保证错误信息能够立即输出。2._IOLBF采用行缓冲I/O。在这种情况下当在输入或输出中遇到换行符\n时标准I/O才会执 行文件 I/O操作。对于输出流在输出一个换行符前将数据缓存除非缓冲区已经被填满当输 出换行符时再将这一行数据通过文件 I/O write()函数刷入到内核缓冲区中对于输入流每次读 取一行数据。对于终端设备默认采用的就是行缓冲模式譬如标准输入和标准输出。3._IOFBF采用全缓冲I/O。在这种情况下在填满stdio缓冲区后才进行文件I/O操作read、write。 对于输出流当 fwrite写入文件的数据填满缓冲区时才调用write()将stdio缓冲区中的数据刷入 内核缓冲区对于输入流每次读取 stdio缓冲区大小个字节数据。默认普通磁盘上的常规文件默 认常用这种缓冲模式。size指定缓冲区的大小。void setbuf(FILE *stream, char *buf);》setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);void setbuffer(FILE *stream, char *buf, size_t size);》setvbuf(stream, buf, buf ? _IOFBF : _IONBF, size);标准输出默认是行缓冲模式只有输出了换行符时才会将换行 符这一行字符进行输出显示也就是刷入到内核缓冲区在没有输出换行符之前会将数据缓存在 stdio 缓冲区中。无论我们采取何种缓冲模式在任何时候都可以使用库函数 fflush()来强制刷新将输出到stdio缓冲区中的数据写入到内核缓冲区通过 write()函数stdio缓冲区该函数会刷新指定文件的stdio 输出缓冲区关闭文件也会进行刷新如果使用_exit或_Exit()终止程序则不会刷新4.两者互相转化库函数 fileno()可以将标准I/O中使用的FILE指针转换为文件I/O中所使用的文件描述符而 fdopen() 则进行着相反的操作int fileno(FILE *stream);FILE *fdopen(int fd, const char *mode);在这样使用的时候要注意刷新的问题。3.文件属相部分在windows中文件是以.后缀进行区分的在linux中文件不是以.后缀进行划分的不过文件终归是要给人看的所以还是得按照正常的格式进行编写。在linux中可以通过statls命令查看文件的属性。 - 普通文件 d 目录文件 c 字符设备文件 b 块设备文件 l 符号链接文件 s 套接字文件 p 管道文件关于stat命令与file命令的区别stat命令stat读取的是文件系统的 inode 信息包括权限、大小、时间戳、设备号等它不关心文件内容file命令