linux文件操作函数

目录标题

    • man帮助命令
    • 文件io库函数
      • 操作句柄(fopen、fclose)
      • 以字节为单位的IO函数(fgetc、fputc、putchar、getchar)
      • 操作读写位置函数(fseek、rewind、ftell)
      • 以字符串为单位的IO函数(fgets、gets、fputs、puts)
      • 二进制文件读写(fread、fwrite)
    • 文件io系统调用
      • 打开关闭open、close函数
      • 读写read、write函数
      • 万能fcntl函数(更改文件属性)
      • 文件指针偏移lseek函数
      • 更改文件大小truncate函数
      • 获取文件属性stat、lstat函数
      • 硬链接link、unlink函数
      • 目录操作函数opendir、closedir、readdir
      • 重定向dup、dup2函数
      • 其他函数(access、chmod、chdir、getcwd、rename、symlink、readlink、rewinddir、telldir、seekdir)
    • read、write实现cp命令
    • fgetc、fputc函数实现cp命令
    • link、unlink实现mv命令
    • 使用目录操作函数实现ls

man帮助命令

1   Executable programs or shell commands  可执行程序或者shell命令
2   System calls (functions provided by the kernel)  系统调用,内核提供的函数
3   Library calls (functions within program libraries)  库函数调用(程序库中的函数)
4   Special files (usually found in /dev)  特殊文件
5   File formats and conventions eg /etc/passwd  文件格式和规范
6   Games  游戏
7   Miscellaneous (including macro packages and conventions), e.g. man(7),groff(7)
8   System administration commands (usually only for root) 系统管理命令
9   Kernel routines [Non standard]  内核例程

eg:man 2 open 

文件io库函数

操作句柄(fopen、fclose)

#include

FILE *fopen(const char *path, const char *mode); 打开文件
int fclose(FILE *fp); 关闭文件

//mode参数
/*“r”:只读,文件必须存在。
“w”:只写,如果不存在则创建,存在则覆盖。
“a”:追加,如果不存在则创建。
“r+”:允许读和写,文件必须存在。
“w+”:允许读和写,文件不存在则创建,存在则覆盖。
“a+”:允许读和追加,文件不存在则创建*/
1、fopen函数
    成功返回文件指针,失败返回NULL
2、fclose函数
    成功返回0,失败返回-1

以字节为单位的IO函数(fgetc、fputc、putchar、getchar)

#include
int fgetc(FILE *stream);
int getchar(void);
int fputc(int c, FILE *stream);
int putchar(int c);

fgetc 函数从指定的文件中读一个字节。
getchar从标准输入读一个字节,调用 getchar() 相当于 fgetc(stdin)。
fputc 函数向指定的文件写入一个字节。
putchar 向标准输出写一个字节,调用 putchar() 相当于调用 fputc(c, stdout)1stdin等是FILE *类型,属于标准I/O,在<stdio.h>2、STDIN_FILENO等是文件描述符,是非负整数,一般定义为0, 1, 2
	属于没有buffer的I/O,直接调用系统调用,在<unistd.h>
3、上面的函数,成功返回0,错误或读到文件末尾时将返回 EOF,即 -1

操作读写位置函数(fseek、rewind、ftell)

#include
int fseek(FILE *stream, long offset, int whence);
void rewind(FILE *stream);
long int ftell(FILE *stream);

1、fseek函数:文件偏移
    成功,返回0,失败返回非0值,并设置error的值,可以用perror()函数输出错误
    whence:从何处开始移动,取值:SEEK_SET | SEEK_CUR | SEEK_END
    offset:移动偏移量,取值:可取正 |fseek(fp, 4, SEEK_SET);     // 从文件头向后移动4个字节
    fseek(fp, 4, SEEK_CUR);     // 从当前位置向后移动4个字节
    fseek(fp, -4, SEEK_END);    // 从文件尾向前移动4个字节
2、rewind函数
    返回到文件开头
    rewind(fp)相当于 fseek(fp, 0, SEEK_SET)
3、ftell函数
    返回当前文件位置
    // 实现计算文件字节数的功能
	fseek(fp, 0, SEEK_END);
	ftell(fp);

以字符串为单位的IO函数(fgets、gets、fputs、puts)

char *fgets(char *s, int size, FILE *stream);
char *gets(char *s);
int fputs(const char *s, FILE *stream);
int puts(const char *s);

	fgets 函数从 stream 所指文件读取以 ‘\n’ 结尾的一行,包括 ‘\n’ 在内,
		存到缓冲区中,并在该行结尾添加一个 ‘\0’ 组成完整的字符串。
		如果文件一行太长,fgets 从文件中读了 size-1 个字符还没有读到 ‘\n’,
		就把已经读到的 size-1 个字符和一个 ‘\0’ 字符存入缓冲区,
		文件行剩余的内容可以在下次调用 fgets 时继续读。
    fputs 向指定文件写入一个字符串,
	    缓冲区保存的是以 ‘\0’ 结尾的字符串,
	    与 fgets 不同的是,fputs 不关心字符串中的 ‘\n’ 字符

二进制文件读写(fread、fwrite)

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
参数:
	ptr:存放文件内容地址
	size 读取的块大小
	nmemb 块数(读取文件大小 = 块数*每块大小)
	stream 文件指针
返回值:
	成功读取到文件块数
size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);
参数:
	ptr:写入文件内容地址
	size 块大小
	nmemb 块数(写入文件大小 = 块数*每块大小)
	stream 文件指针
返回值:
	成功:写入到文件块数
eg:
struct t{
    int   a;
    short b;
};
struct t val = {1, 2};
FILE *fp = fopen("file.txt", "w");
fwrite(&val, sizeof(val), 1, fp);
fclose(fp);

文件io系统调用

打开关闭open、close函数

使用头文件<fcntl.h>
int open(const char* pathname,int flags);
int open(const char* pathname,int flags,mode_t );
int close(int fd);
参数:
	pathname 文件名
	flag:打开权限
		O_RDONLY(只读)O_WRONLY(只写)O_RDWR(可读可写)O_APPEND(追加)C_CREAT(创建)、O_EXCL、O_TRUNC(截断)O_NONBLOCK(非阻塞)
	创建文件时,指定文件访问权限,权限同时受umask影响,
	文件权限 = mode&~umask
返回值:
	成功:文件描述符
	失败:-1

读写read、write函数

size_t read(int fd,void* buf,size_t count);
参数:
	fd 文件描述符
	buf 存储数据缓冲区
	count 缓冲区大小
返回值:
	0 表示读到文件结尾
	成功:读取到的文件字节数
	失败:-1设置error
	-1并且errno = EAGAIN 或 EWOULDBLOCK,
    说明不是read 失败,而是以非堵塞方式读取一个设备文件(网络),并且文件无数据	
    
size_t write(int fd,void* buf,size_t count);
参数:
	fd 文件描述符
	buf 要写入的数据
	count 要写入的数据大小
返回值:
	成功:成功写入的字符
	失败:-1设置errno

万能fcntl函数(更改文件属性)

int fcntl(int filedes,int cmd, ... /*int arg*/);
更改文件属性
    int flgs = fcntl(fd, F_GETFL);
    flgs |= O_NONBLOCK
    fcntl(fd, F_SETFL, flgs);
cmd参数
    获取文件状态: F_GETFL
    设置文件状态: F_SETFL

文件指针偏移lseek函数

off_t lseek(int fd,off_t offset,int whence);
    参数:
        fd 文件描述符
        offset 偏移量
        whence 起始偏移位置:SEEK_SET/SEEK_CUR/SEEK_END
    返回值:
        成功:较起始位置偏移量
        失败:-1 errno
        
//使用lseek函数改变文件大小
    lseek(fd, 9, SEEK_END);  //将文件给扩展长度到10
    write(fd, "\0", 1);
//使用lseek函数获取文件大小
	int len = lseek(fd, 0, SEEK_END);//获取文件的长度

更改文件大小truncate函数

int truncate(const char* path,off_t length);//更改文件大小
int truncate(int fd,off_t length);//更改文件大小
返回值:成功返回0,错误返回-1
//使用truncate函数更改文件大小
int ret = truncate("dict.cp", 250);
int ret2 = ftruncate(fd,250);

获取文件属性stat、lstat函数

int stat(const char *path, struct stat *buf);//stat 会拿到符号链接指向那个文件或目录的属性
int lstat(const char *path, struct stat *buf);//lstat不会穿透
int fstat(int fd, struct stat *buf);
参数:
    path: 文件路径
    buf:(传出参数) 存放文件属性,inode 结构体指针。
返回值:
    成功: 0
    失败: -1 errno
获取文件大小: buf.st_size
获取文件类型: buf.st_mode
获取文件权限: buf.st_mode
//stat结构体
struct stat {
    dev_t st_dev; /* ID of device containing file 文件设备编号*/
    ino_t st_ino; /* inode number 节点号*/
    mode_t st_mode; /* protection 文件的类型和存取的权限*/
    nlink_t st_nlink; /* number of hard links 连到该文件的硬连接数目,刚建立的文件值为1*/
    uid_t st_uid; /* user ID of owner 用户ID*/
    gid_t st_gid; /* group ID of owner 组ID*/
    dev_t st_rdev; /* device ID (if special file) (设备类型)若此文件尾设备文件,则为其设备编号*/
    off_t st_size; /* total size, in bytes 文件字节数(文件大小)*/
    blksize_t st_blksize; /* blocksize for filesystem I/O 块大小(文件系统的I/O缓冲区大小),类型为unsigned long类型*/
    blkcnt_t st_blocks; /* number of 512B blocks allocated ,分配的512字节的块数,类型为unsigned long类型*/
    time_t st_atime; /* time of last access 最后一个访问时间*/
    time_t st_mtime; /* time of last modification 最后更改的时间*/
    time_t st_ctime; /* time of last status change inode的更改时间*/
};

//宏定义
S_ISREG(m) is it a regular file? 是否是一个常规文件
S_ISDIR(m) directory? 是否是一个目录
S_ISCHR(m) character device? 是否是一个字符设备
S_ISBLK(m) block device? 是否是一个块设备
S_ISFIFO(m) FIFO (named pipe)? 是否是输入输出(管道)
S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.) 是否是符号链接
S_ISSOCK(m) socket? (Not in POSIX.1-1996.) 是否是socket
eg:
if(S_ISDIR(mystat.st_mode)){
   printf("it is a dir");
}

硬链接link、unlink函数

int link(const char *oldpath, const char *newpath);
int unlink(const char *pathname);
函数在执行成功时则返回0,失败时则返回-1,错误原因存于errno。

目录操作函数opendir、closedir、readdir

#include 
#include 
DIR * opendir(char *name);
int closedir(DIR *dp);
struct dirent *readdir(DIR * dp);
返回结构:
    struct dirent {
        ino_t d_ino; / inode number /
        off_t d_off; / offset to the next dirent /
        unsigned short d_reclen; / length of this record /
        unsigned char d_type; / type of file /
        char d_name[256]; / filename */
	};
//该三个函数主要是用于遍历目录使用,获取文件、目录名字

重定向dup、dup2函数

#include 
int dup(int oldfd);
int dup2(int oldfd, int newfd);//oldfd 拷贝给 newfd。返回 newfd
oldfd: 已有文件描述符
返回:新文件描述符,这个描述符和 oldfd 指向相同内容。
    
//使用fcntl函数实现dup2
    fcntl(fd,F_DUPFD,0);
	fcntl(fd,F_DUPFD,7);
//被占用的,返回最小可用的。
//未被占用的, 返回=该值的文件描述符。
//其中的第三个参数0,这个表示 0 被占用,fcntl 使用文件描述符表中的最小文件描述符返回
//假设传一个 7,且 7 未被占用,则会返回 7

其他函数(access、chmod、chdir、getcwd、rename、symlink、readlink、rewinddir、telldir、seekdir)

access函数:用于测试指定的文件是否存在/拥有某种权限
    int access(const char *pathname,int mode);
    mode:R_OK,W_OK,X_OK,F_OK
    成功/具备该权限:0;失败/不具备 -1 设置errno为相应值。
    int ret = access(""./nihao.txt",F_OK);
    if(ret == 0){
        printf("该文件存在\n");
    }else{
        printf("该文件不存在\n");
    }
                     
chmod函数:用于修改文件的属性
    int chmod(const char *path, mode_t mode);
    成功:0;失败:-1设置errno为相应值
	int fchmod(int fd, mode_t mode);
    成功:0;失败:-1设置errno为相应值
    int ret = chmod("./nihao.txt", 0777);
    int ret = fchmod(fd, 0777);
                     
chdir函数:改变当前工作目录
    int chdir(const char *path );
    成功:0;失败:-1设置errno为相应值
    if(chdir("..") == -1){
        perror("Couldn`t change current working diretory!");
        return 1;
	}
                     
getcwd函数:获取进程当前工作目录	(3,标库函数)
	char *getcwd(char *buf, size_t size);	
    成功:buf中保存当前进程工作目录位置。失败返回NULL。
                     
rename函数:重命名一个文件。
 	int rename(const char *oldpath, const char *newpath); 
 	成功:0;失败:-1设置errno为相应值
                     
symlink函数:创建一个符号链接
	int symlink(const char *oldpath, const char *newpath);	
    成功:0;失败:-1设置errno为相应值
                     
readlink函数:读取符号链接文件本身内容,得到链接所指向的文件名。
	ssize_t readlink(const char *path, char *buf, size_t bufsiz);	
    成功:返回实际读到的字节数;失败:-1设置errno为相应值。
                     
rewinddir函数:回卷目录读写位置至起始。
	void rewinddir(DIR *dirp);	
    返回值:无。
                     
telldir函数:获取目录读写位置
		long telldir(DIR *dirp); 
        成功:与dirp相关的目录当前读写位置。失败-1,设置errno
                     
seekdir函数:修改目录读写位置
		void seekdir(DIR *dirp, long loc); 返回值:无
		参数loc一般由telldir函数的返回值来决定。

read、write实现cp命令

#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc,char* argv[]){
	
	char buff[1024];
	int n =0;
	int fd1 = open(argv[1],O_RDONLY);//read
	int fd2 = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0664);//如果没有则创建
	
    if(fd1 == -1){
		perror("open argv[1] error");
		exit(1);
	}
    
    if(fd2 == -1){
        perror("open argv[2] error");
        exit(1);
    }
    
	while((n = read(fd1,buff,1024)) != 0){//读到结尾会返回0
        if(n < 0){
            perror("read error");
            break;
        }
		write(fd2,buff,n);
	}
    
	close(fd1);
	close(fd2);
	return 0;
}

fgetc、fputc函数实现cp命令

#include 
#include 
#include 
#include 

int main(int argc,char* argv[]){
	FILE *fp,*fp_out;
	int n = 0;

	fp = fopen(argv[1],"r");
	if(fp == NULL){
		perror("open argv1 error");
		exit(1);	   
	}
	
	fp_out = fopen(argv[2],"w");
	if(fp_out == NULL){
		perror("open argv2 error");
	}
	while((n = fgetc(fp))!=EOF){
		fputc(n,fp_out);
	}

	fclose(fp);
	fclose(fp_out);

	return 0;
}

link、unlink实现mv命令

#include 
#include 
#include 
#include 
#include 

int main(int argc,char **argv){
	link(argv[1],argv[2]);
	unlink(argv[1]);
	return 0;
}
/*执行结果
ubuntu@ubuntu:~/LearnCPP/linux_test/link_test$ ./link_test nihao.txt nihao2.txt
ubuntu@ubuntu:~/LearnCPP/linux_test/link_test$ ls
link_test  link_test.c  makefile  nihao2.txt
*/

使用目录操作函数实现ls

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

void read_dir(char* dir,void (*func)(char*));

//判断是否是目录,打印文件
void isFile(char* name){
	int ret = 0;
	struct stat mystat;
	ret = stat(name,&mystat);//获取文件属性
	
	if(ret == -1){
		perror("stat error");
		return;
	}
	
	if(S_ISDIR(mystat.st_mode)){//判断是否是目录
		read_dir(name,isFile);
	}
	
	printf("%s\t\t%ld\n",name,mystat.st_size);//打印文件名字和大小

	return;
}

//读取文件,更新目录
void read_dir(char* dir , void (*func)(char*)){
	DIR* dp;
	struct dirent *sdp;
	char path[256];

	dp = opendir(dir);
	if(dp == NULL){
		perror("opendir error");
		return ;
	}
	
	while((sdp = readdir(dp)) != NULL){
		if((strcmp(sdp->d_name,"."))==0 || strcmp(sdp->d_name,"..")==0){//防止出现死循环
			continue;
		}
        //sdp->d_name表示的是文件或者目录的名称
		sprintf(path,"%s/%s",dir,sdp->d_name);//更新路径

		(*func)(path);//函数指针调用
	}

}

int main(int argc,char* argv[]){

	if(argc == 1){
		isFile(".");
	}else{
		isFile(argv[1]);
	}
	return 0;
}

/*执行结果
ubuntu@ubuntu:~/LearnCPP/linux_test/ls_R_test$ ./ls_R_test 
./makefile		88
./ls_R_test		9080
./ls_R.c		967
.		4096
*/

你可能感兴趣的:(linux,linux,c语言,学习)