Linux 下C编程(一)文件基础

博主原创,转载请加上http://www.cnblogs.com/jikexianfeng/p/5769357.html

一.课程概要
1.文件描述符
2.文件操作和内核数据结构
3.文件原子操作

二.正文
(一).文件描述符
1.文件描述符简介
1).对于linux内核而言,所有的文件打开都是有文件描述符引用的.
2).文件描述符是一个非负整数(返回-1为标准出错),并且与文件是相对应的.
3).当打开一个现存文件或创建一个新文件时,内核向进程返回一个文件描述符.
4).当读写文件时,需要(用open或creat返回值)将文件描述符当做参数传递给相应的函数(read,write).
5).代码实践 gcc -o bin/fd_test src/fd_test.c
遇到问题:当(./bin/fd_test)执行代码时,打开文件的失败(返回值为-1),进入bin目录执行fd_test时成功(返回值为3)?
6).返回值为什么为3?
当程序运行时,系统会打开3个文件,标准输入0(STDIN_FILENO),标准输出1(STDOUT_FILENO),标准出错2(STDERR_FILENO),这些都定义在头文件<unistd.h>中.所以打开的文件是以3开始计数的.
7).文件描述符的范围时0~OPEN_MAX.这个宏值.很多系统时63,linux是1024.
(二),实现shell命令
1.自定义头文件
1).编写一个具有的cp功能的自定义头文件 io.h(传入的为文件描述符)
2) 路径
include/io.h
src/io.c
3).编译生成二进制文件
gcc -c -Iinclude src/io.c
2.编写mcp上层文件
1).路径
src/mcp.c
2).编译
gcc -Iinclude src/io.c src/mcp.c -o bin/mcp
3.编写mcat上层文件
1).路径
src/mcat.c
2).编译
gcc -Iinclude src/io.c src/mcp.c -o bin/mcp

(三).文件操作和内核数据结构
1.操作文件I/O的五个函数
1).open
2).read
3).wirte
4).lseek
5).close
2.操作文件描述符号的函数
1).dup
2).dup2
3.改变文件状态函数
1).fcntl
4.文件在内核中的数据结构(有3种数据结构表示)
1).文件描述符表
2).文件表项
3).V节点
5.文件原子操作

(四).函数详解
1.open函数(打开文件)
1).头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
2).原型
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
const char *pathname 为要打开的文件路径
int flags 为读/写标志位
O_RDONLY 自读打开
O_WRONLY 只写打开
or O_RDWR 读写打卡
O_APPEND 每次写时都加到文件尾端
O_CREAT 若此文件不存在则创建它,使用此选择项时,须同说明第三个参数mode,用其说明文件的权限
O_EXCL 如果同时指定了O_CREAT,而文件存在,则出错.这可测试一个文件是否存在,如果不存在则创建此文件成为一个原子操作
O_TRUNC 如果此文件存在,而且为只读或只写成功打开,则将其长度截断为0
O_SYNC 每次write都等物理I/O操作完成
O_NONBLOCK 如果pathname指定的是一个FIFO,一块特殊文件或一个字特殊文件,则此选择项为此文件的本次打开操作和后续I/O操作设置非阻塞方式.
mode_t mode 为可选参数,只有创建文件时候,才选择使用
返回值:成功返回文件描述符,失败返回-1.

2.creat函数(创建文件,默认为只写方式打开)
1).头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
2).原型
int creat(const char *pathname, mode_t mode);
const char *pathname 为要打开的文件路径
mode_t mode 文件的权限
返回值:成功返回文件描述符,失败返回-1.

3.close 函数(关闭文件描述符)
1).头文件
#include <unistd.h>
2).原型
int close(int fd);
int fd 为文件描述符
返回值:成功返回0,失败返回-1.
当一个进程中制定时,它打开的所有文件都有内核自动关闭.

4.read 函数(从文件中读内容)
1).头文件
#include <unistd.h>
2).原型
ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset);
ssize_t read(int fildes, void *buf, size_t nbyte);
int fildes 文件描述符
void *buf 缓存区
size_t nbyte 需要读数据到的字节数
返回值:成功返回读到的字节数,若已读到文件尾部且文件没有内容,则为0,失败返回-1.
3).有多种情况使读到的字节数少于要求读的字节数
(1).在读普通文件时,在读到要求字节数之前已到达文件尾端.
(2).当从终端设备读时,通常最多读一行.
(3).当从网络读时,网络中的缓存机构可能造成返回值小于所要求读的字节数.
(4).某些面向记录的设备,如磁带,每次最多返回一个记录.
(5).进程由于信号造成的中断(正在读的时候,进程终止).

5. write函数(向文件中写内容)
1).头文件
#include <unistd.h>
2).原型
ssize_t pwrite(int fildes, const void *buf, size_t nbyte,off_t offset);
ssize_t write(int fildes, const void *buf, size_t nbyte);
int fildes 文件描述符
const void *buf, size_t nbyte 缓存区
size_t nbyte 需要向文件写入的字节数
返回值:成功返回已写到的字节数,失败返回-1.

6.lseek 函数(改变读写文件时读写指针位置)
1).头文件
#include <unistd.h>
#include <sys/types.h>
2).原型
off_t lseek(int fd, off_t offset, int whence);
int fd 文件描述符
off_t offset 文件偏移量
int whence 位置
若whence是SEEK_SET,则将该文件的位移量设置为距文件开始处 offset 个字节.
若whence是SEEK_CUR,则将该文件的位移量设置为当前值加 offset, offset可以为正或负.
若whence是SEEK_END,则将该文件的位移量设置为文件长度加 offset, offset可以为正或负.

8.dup和dup2(文件描述符操作)
1).头文件
#include <unistd.h>
2).原型
int dup(int oldfd);
int dup2(int oldfd, int newfd);
用来复制文件描述符,在进程通信的时候,改变进程标准输入和标准输出设备,
返回值:成功返回新的文件描述符,失败返回-1.
3).使用dup2从定向文件标准输入/输出.
(1).编写dup2_test.c
(1).路径
src/dup2_test.c
(2).编译
gcc -o bin/dup2_test src/dup2_test.c

9.fcntl(可以改变已经打开文件的性质.)
1).头文件
#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
2).原型
int fcntl(int fd, int cmd, ... /* arg */ );
int fd 文件描述符
int cmd 文件状态设置
返回值:成功(则依赖于cmd)返回一个大于0的数,失败返回-1.
3).编写mcat上层文件
(1).路径
src/flag_test.c
(2).编译
gcc -Iinclude src/io.c src/flag_test.c -o bin/flag_test
(3)./bin/flag_test test.txt zhangjianqi!

10.文件在内核中的数据结构(详情见./picture/内核中的数据结构.png)
一个打开的文件在内核中有三种数据结构,第一个是文件描述符表,第二个是文件表项,第三个是v节点,其中当一个进程启动的时候,他会自动打开一个FILE结构体,这个FILE结构体里面就是一些fb文件描述符的字段,那么如何通过文件描述符这个字段来找到这个文件了,咱们来看一个草图,当一个进程启动的时候,它会自动的打开一些文件描述符,有0(标准输入)1(标准输出)2(标准出错),然后通过文件描述符找到内核当中的一个数据结构FDT,第2个是文件表项的指针,文件描述文件表里面第一个内容是文件描述符的标志,第二个是被表象的指针,就是指向文件表项的指针,当它找到FI这个文件表项的时候,文件表项里面又记录了文件的状态标志,也就是只读,只写,或O_APPEND等状态标志,以及当前文件的偏移量,文件表项里面还记录了V节点的表项指针,他还用来指向下一个数据结构V节点.
v节点里面又存放了文件的类型文件的创作者或者操作时间,也就是ls -l看到的所以内容,其中V节点里面存放了最重要的内容是i-node(快设备的标号,也就是ls -i看到的所以内容),然后通过i-node来找到这个磁盘上的文件.

11.文件原子操作
1).稳健追加
打开文件时使用 O_APPEN 标志,进程对文件偏移量调整和数据追加成原子操作.内核每次对文件写之前,都将进程的当前偏移量设置为该文件尾端,这样不在需要lseek来调整偏移量.
2).文件创建
对open函数的 O_CREAT 和 O_EXCL的使用,而该文件存在,open将失败,否则创建该文件,并且使得文件是否存在的判定和创建过程为原子操作.

代码下载:https://git.oschina.net/jikexianfeng/LINUX.git

时间: 2024-10-21 14:04:05

Linux 下C编程(一)文件基础的相关文章

Linux下C编程-----IO/文件操作 模拟linux ls程序显示文件系统树形结构(2)

Linux下的IO/文件操作练习,知识虽然简单 但是往往基础容易被忽略,偶尔的练习是有必要的. 练习printf /************************************************************************* > File Name: printf.c > Author: > Mail: > Created Time: Wed 11 Feb 2015 01:08:15 AM PST ***********************

Linux下C编程-----IO/文件操作/内存映射 实现简单记录存储(3)

利用linux下的文件内存映射可以实现进程共享数据,我们可以把一个文件映射到虚拟内存中使多个进程进行共享, 到这里我们大概能想到他能应用到的领域 是很广泛的 主要涉及到 mmap  munmap   msync 三个函数的应用 下面贴代码 下面一段代码是为文件建立一个简单的记录存储,并且通过内存映射修改文件内容 /************************************************************************* > File Name: memdb

Linux 下互联网络编程的基础知识

2019-10-07 关键字:Linux 网络编程基础 TCP/IP 协议里有两种不同的协议: 1.TCP协议 用于检测网络传输中的差错. 2.IP协议 用于对不同网络进行互联. 简单说就是 TCP 负责纠错,IP 负责传输. 网络体系结构: 网络体系结构就是将复杂的网络通信过程按照一定的规则进行分层,从而能使整个的网络通信过程更加清晰. 这一分层的核心思想有二: 1.每一层实现不同的功能,并对其上层做透明传输. 2.每一层都会使用到其下一层所提供的服务,并对其上一层提供服务. 早期的网络体系结

linux下多线程编程

最近研究mysql源码,各种锁,各种互斥,好在我去年认真学了<unix环境高级编程>, 虽然已经忘得差不多了,但是学过始终是学过,拿起来也快.写这篇文章的目的就是总结linux 下多线程编程,作为日后的参考资料. 本文将介绍linux系统下多线程编程中,线程同步的各种方法.包括: 互斥量(mutex) 读写锁 条件变量 信号量 文件互斥 在介绍不同的线程同步的方法之前,先简单的介绍一下进程和线程的概念, 它们的优缺点,线程相关的API,读者——写者问题和哲学家就餐问题. 基础知识 1. 进程和

根据《linux兵书》目录 在kali上操作 第8章 Linux下的编程

第8章  浑水摸鱼:Linux下的编程 175 8.1  Linux下常用的开发工具 176 8.1.1  GCC 176 8.1.2  CVS 176 8.1.3  Perl 176 8.1.4  Linux上的Delphi--Kylix 177 8.2  Linux下的Vi文本编辑器 177 8.2.1  Vi编辑器介绍 178 8.2.2  启动Vi编辑器 179 8.2.3  显示Vi中的行号 180 8.2.4  光标移动操作 181 8.2.5  屏幕命令 182 8.2.6  文本

Linux下Socket编程

http://blog.chinaunix.net/uid-20733992-id-3450058.html 原文地址:Linux下Socket编程 作者:yulianliu1218 Linux下Socket编程 什么是Socket Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序.要学Internet上的TCP/IP网络编程,必须理解Socket接口. Socket接口设计者最先是将接口放在Unix操作系统里面

Linux下Shell编程

Linux的shell编程 1.什么是shell? 当一个用户登录Linux系统之后,系统初始化程序init就为每一个用户运行一个称为shell(外壳)的程序. shell就是一个命令行解释器,它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序,用户可以用shell来启动.挂起.停止甚至是编写一些程序.一般的Linux系统都将bash作为默认的shell. 2.几种流行的shell 目前流行的shell有ash.bash.ksh.csh.zsh等,可以用下面的命令来查看she

linux 下 poll 编程

poll 与 select 很类似,都是对描述符进行遍历,查看是否有描述符就绪.如果有就返回就绪文件描述符的个数将.poll 函数如下: #include <poll.h> int poll(struct pollfd *fdarray, unsigned long nfds, int timeout) 第一个参数指向结构数组第一个元素的指针,每个数组都是一个 pollfd 结构iouyonghu制定额是某个给定描述符的条件. struct pollfd { int fd; short eve

Linux下shell编程实例

1. 判断一文件是不是块或字符设备文件,如果是将其拷贝到 /dev 目录下 read -p "input a file:" filename if [ -b $filename -o -c $filename ] then cp $filename /dev/ fi 2.编写一个脚本,进行简单的减法运算,要求提示输入变量 #!/bin/bash read -p "input a number:" num1 read -p "input another nu

linux下Bash编程组合测试及编写脚本(五)

linux下Bash编程组合测试及编写综合脚本(五) 1.Bash编程组合测试条件 -a: 与关系 -o: 或关系 !: 非关系 表示方法1:[ $# -gt 100 -a $# -le 500 ] 表示方法2:[ $# -gt 100 ] && [ $# -le 500 ] 2.编写一个任意添加与删除用户的脚本,要求如下: 2.1:如果脚本选项是--add:,将添加用户; 如果选项是--del,将删除用户,如果是--help显示帮助信息 2.2:脚本选项后面的参数可任意指定多个用户并且用