linux下系统编程学习笔记之文件操作(一)

这部分内容学了好长时间了,几乎都要忘光了,所以拿出来复习一下,顺便做下笔记,而且要每天都要看一遍,不能再丢下了,如果总是这样就总在不断地学习这一个知识点,争取做到,学一个就会一个,不能学一个就扔一个,这样每次都能只是0-60分之间,永远能提升不了。闲话少说,开始写。

linux下一般都会有如下几个目录:

/bin 用于存放普通户用执行的命令,任何用户都可以执行该目录的命令,如ls、cd等。

/boot 存放linux内核及启动系统是时所需文件,为保证启动文件更加可靠,通常把该目录放在独立分区上。

/dev 设备文件的存目录。

/etc 用于存放系统的配置文件,如用户账号和密码存放在/etc/password 和 /etc/shadow中。

/home 普通用户主目录,每个用户在该目录下都有一个与用户名同名的目录。

/lib 用于存放各种库文件

/proc 是一个虚拟文件系统,只有系统运行是才存在,可以通过访问该目录中的文件。获取系统状态的状态信息,并修改某些系统配置信息。

/root  超级用户的主目录。

/sbin 存放用于管理系统的命令

/tmp 临时文件目录。

/usr 用于存放系统应用程序及相关文档,如说明文档,帮助文件等。

/var 用于存放系统中经常变化的文件,如日志文件和邮件等。

 

在linux下对物理磁盘的访问,都是通过设备驱动程序进行的,对设备驱动程序的访问有两种方式,一:通过设备本身提供的接口,这种方式会绕过文件系统直接读写磁盘上的内容。一般不建议使用这种方法。二:通过虚拟文件系统(VFS):不存在的,只存在内存当中,将不同的文件系统整合在一起,提供统一的编程接口(API)以供使用。

 

linux下文件的分类:

普通文件:最常见,包含了某种形式的数据。

目录文件:就是目录,有相关属性,其内容就是目录下的文件和目录。

字符特殊文件:用于表示系统中字符类型设备,如鼠标、键盘等。

块特殊文件:用于表示系统中块类型的设备,如硬盘、光驱等,对这些设备上的数据访问都通常以块的方式进行,一次最少读一个块。

FIFO:这种文件用于进程间通信。也称命名管道。

套接字(SOCKET):用于网络通信,也可用于进程通信。

符号链接文件:只想另外一个文件,是另一个文件的引用。

 

在介绍相关函数操作函数之前,必须介绍一下系统调用和库函数的区别:

系统调用:creat open close read write lseek

c语言标准库函数:fopen fclose fread fwrite fseek

c语言标准库函数都是调用系统调用来实现的,如果要书写跨平台的代码,尽量使用库函数,毕竟文件描述符是linux特有的东西。在0-NR_open之间,NR_open的值为255,

文件描述符0,表示标准输入:一般指键盘,文件描述符1,表示标准输出:一般指显示器,文件描述符3表示标准出错:一般也指显示器,打开一个文件这三个都是默认打开的。

 

下面开始介绍文件操作的函数:用man page都可以查看原型,但是如果这个函数即使一个命令也是一个函数的话就需要看man page的第一页,如:man 2 chmod

1、chmod/fchmod——对文件的访问权限进行修改()

函数原型:

int  chmod (const char * path, mode _t mode);

int fchmod(int file, mode_t mode);

这两个函数都是改变文件的修改权限,区别是chmod以文件名作为第一个数的参数。而fchmod是以文件描述符作为第一个参数的。第二个参数就是需要修改的权限。

成功返回0,失败返回-1,并设置相应的errno。

 

2、open close read write lseek

open:打开一个文件,返回一个文件的文件描述符

int open(const char * pathname, int flag);

int open(const char * pathname, int flag, mode_t mode);

第一个参数是打开文件的带路径的文件名,可以使相对路径也可以使绝对路径。第二个参数打开的方式:

O_RDONLY只读打开 O_WRITE只写方式打开 O_RDWR以可读可写的方式打开。这三种的互斥的,打开一个文件三种方式必选其一,而且只能选一个。

还有其他的方式, 下面的这些方式可以和上面的方式做或操作:

O_CREAT若文件不存在则创建,只有当用到此选项时,参会用到第三个参数,表示创建文件的访问权限。

O_APPEND已追加的方式打开文件,填入的信息都会添加到文件末尾

O_TRUNC:若文件已存在,则截断。

O_SYNC:一同步的方式打开一个文件,所有的修改都会被阻塞,直到物理磁盘的数据同步以后才返回。

 

close:关闭文件

int close (int fd);

成功返回0, 失败返回-1;

 

read:从打开的文件中读数据

ssize_t read(int fd, void * buf, size_t count);

从fd所指向的文件中读取 count个字节,放在buf所指向的地址中。

成功返回实际读取的字节数,失败返回-1.设置相应的errno

 

write:从文件中读取数据

ssize_t write(int fd, void * buf, size_t count);

将buf所致单元中的 count个字节的数据写入fd所指向的文件中。

函数调用成功返回实际写入的字节数,失败返回-1,设置相应的errno。

 

read和write操作,都会引起文件读写指针的移动。

 

lseek:文件读写指针的移动

off_t lseek(int files, off_t offset, int when);

每个打开的文件都会有一个读写位置,lseek用来控制文件的读写位置。第一个参数:打开的文件描述符,第二个参数是表示:移动多少个字节,第三个参数表示:从哪里开始移动

SEEK_SET:从文件开头开始移动;

SEEK_CUR:从当前位置开始移动;

SEEK_END:从文件末尾开始移动;

值得注意的是,lseek可以将指针移动到EOF之后,如果不进行写操作,文件的大小事不会改变的。

lseek的常用法:

lseek(int file , 0, SEEK_STE);将读写文件移动到开头。

lseek(int file , 0, SEEK_CUR);获取文件指针的当前值。

lseek(int file , 0, SEEK_END);将文件指针移动到文件末尾。

 

下面上一个例程,是对上面的函数的应用,只有会用了才是真正的学到了。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

int my_err(const char * err_string, int line)
{
	fprintf(stderr, "line:%d", line);
	perror(err_string);
	exit(1);
}

int my_read(int fd)
{
	int len, ret, i;
	char read_buff[64];
	if(lseek(fd, 0, SEEK_END) == -1){
		my_err("lseek", __LINE__);
	}
	if((len = lseek(fd, 0, SEEK_CUR)) == -1){
		my_err("lseek", __LINE__);
	}
	if(lseek(fd, 0, SEEK_SET) == -1){
		my_err("lseek", __LINE__);
	}
	printf("len = %d\n", len);
	if((ret = read(fd, read_buff, len)) < 0){
		my_err("read", __LINE__);
	}
	for(i = 0; i< len; i++){
		printf("%c", read_buff[i]);
	}
	printf("\n");
	return ret;
}

int main(void)
{
	int fd;
	char write_buf[32] = "Hello world!";
//	if((fd = creat("test.c", S_IRWXU)) == -1){
	if((fd = open("test.c",O_RDWR)) == -1){
		my_err("open", __LINE__);
	}
	else{
		printf("the file %d open success\n", fd);
	}
	if(write(fd, write_buf, strlen(write_buf)) != strlen(write_buf)){
		my_err("write", __LINE__);
	}
	my_read(fd);
	printf("/*******************************************************/\n");
	if(lseek(fd, 10, SEEK_END) == -1){
		my_err("lseek", __LINE__);
	}
	if(write(fd, write_buf, strlen(write_buf)) != strlen(write_buf)){

		my_err("write", __LINE__);
	}
	my_read(fd);
	close(fd);
	return 0;
}


__LINE__是预编译器内置的宏,表示行数,类似的宏还有__TIME__,__FUNCTION__,__FILE__分别表示时间,函数名,和文件名,利用这些信息可以帮助我们调试代码。

在终端输入od -c test.c就会发现,当文件指针移动到EOF之后和在写入的数据之间使用\0填充的。如果不进行写数据,文件的大小是不会改变的。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值