一、标准IO
相关头文件:#include <stdio.h>
相关函数:fopen 、 fread、fwrite、fgetc、fputc、fgets、fputs、fseek。
相关数据类型: FILE*
错误处理:perror();
打开文件:
FILE * fp = fopen("xxxx", "mode");
fopen中的mode 分为:r 只读,文件必须存在;
r+可读可写,文件必须存在;
w 只写,会重新建立文件,若存在,则擦除原来的文件长度;
w+ 可读可写,同上;
a 追加只写,文件不存在则创建,存在则再文件尾追加数据,
a+ 追加可读可写,同上。
系统默认3个数据流:stdin(0), stdout(1), stderr(2);
fclose(fp); //关闭流
简单实例:
FILE * fp;
if( (fp = fopen( "1.txt", "r")) == NULL )
{
perror("fail to fopen");
return -1;
}
fclose(fp);
return 0;
fgetc()与fputc();
fgetc(FILE* stream): 参数只要一个FILE指针。作用,从FILE中读取一个字符,FILE文件指针向下一个字符移动。
fputc(int c, FILE*stream):c:为要写入的数值。作用,向FILE中写入一个字符,FILE文件指针向下一个字符移动。
简单实例:从键盘中读取一串字符,写入到stdout缓存中只写入数字。fflush用来刷新缓存。
int c;
while(1)
{
c = fgetc(stdin);
if(( c >= '0') && ( c <= '9')) fputc( c, stdout);
if( c == '\n') break;
}
fflush(stdout);
putchar(10);//换行
return 0;
fgets(char *s, int size, FILE* file),从FILE中读取size大小的数据给s。遇到\0或\n结束,会在最后添加一个\0作为结束
fputs(char *s, FILE *file ),将s写入到file中,\0会被丢弃。
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); 从stream中读取nmemb个项的数据,而每个nmemb的大小为size,放入ptr中。
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream); 将ptr中的数据写入到stream中。
简单实例:mycopy ,将一个文件拷贝至另一个文件中。
#include<stdio.h>
#include<string.h>
#include<errno.h>
#define N 64
int main(int argc, char * argv[])
{
int n;
char buf[N];
FILE * fps, * fpd;
if(argc < 3)
{
printf("Usage: %s <src_file> <dst_file> \n", argv[0] );
return -1;
}
if(( fps = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr,"fail to fopen %s:%s \n",argv[1],strerror(errno));
return -1;
}
if(( fpd = fopen(argv[2], "w")) == NULL)
{
fprintf(stderr,"fail to fopen %s:%s \n",argv[2],strerror(errno));
return -1;
}
while(( n = fread(buf, 1, N, fps)) > 0)
{
printf("%s \n",buf);
fwrite(buf, 1, N, fpd);
}
fclose(fps);
fclose(fpd);
return 0;
}
对于系统来说,频繁的调用底层标准IO,每次都会进行系统调用,会比较耗系统的资源。所以引进了标准文件IO。
二、文件IO
相关头文件:#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
相关函数:open 、 read、write。
相关数据类型: int fd。//文件描述符。从0 向上增长。
错误处理:perror();
详细分析:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
pathname为文件路径.
flags为标识符 常用标识符如下:
O_RDONLY :只读打开文件
O_WRONLY :只写打开文件
O_RDWR : 读写打开文件
O_CREAT :文件不存在则创建,mode用来指定文件rwx
O_EXCL :文件存在则返回错误
O_TRUNC :文件存在则删除原有数据
O_APPEND :追加打开文件。读写位置只想文件末尾。
mode为文件模式
#include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
int fd;
if( (fd = open("./test.txt",O_RDWR|O_CREAT|O_TRUNC, 0777)) < 0 )
{
perror("fail to open");
return -1;
}
close(fd);
return 0;
}
ssize_t read(int fd, void *buf, size_t count); 从fd 中读取数据,存入到buf中,读入数据大小为count,返回值为:实际上读取文件的大小。失败返回-1或错误码。
ssize_t write(int fd, const void *buf, size_t count); 将buf中的数据写入到fd中,数据大小为count,返回值为:实际上写入文件的大小。失败返回-1或错误码。
off_t lseek(int fd, off_t offset, int whence);offset为偏移值,whence为从哪偏移,可选宏为:SEEK_SET 文件起始位置,SEEK_CUR 文件当前位置,SEEK_END文件结束位置。
简单实例:将文件1中的最后10K数据写入到文件2 中。
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#define BUFFER_SIZE 1024
#define SRC_FILE_NAME "./usb.c"
#define DEST_FILE_NAME "./test.txt"
#define OFFSET 10240
int main()
{
int fds, fdd;
unsigned char buff[BUFFER_SIZE];
int read_len;
if((fds = open(SRC_FILE_NAME,O_RDONLY)) < 0)
{
perror("fail to open fds");
}
if((fdd = open(DEST_FILE_NAME,O_WRONLY|O_CREAT)) < 0)
{
perror("fail to open fdd");
}
lseek(fds, -OFFSET, SEEK_END);
while((read_len = read(fds, buff, sizeof(buff))) > 0)
{
write(fdd, buff, read_len);
}
close(fds);
close(fdd);
return 0;
}
文件锁
struct flock {
...
short l_type; /* Type of lock: F_RDLCK, 读锁
F_WRLCK 写锁, F_UNLCK 没有锁*/
short l_whence; /* How to interpret l_start:
SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* Starting offset for lock */
off_t l_len; /* Number of bytes to lock */
/./以上三个确定 锁的起始位置,加锁区域的长度。
pid_t l_pid; /* PID of process blocking our lock 进程号
(F_GETLK only) */
...
};
相关函数:fcntl:
头文件:#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
cmd包括:F_GETLK::检测文件锁状态
F_SETLK:设置lock的文件锁
F_SETLKW::可wait 阻塞的设置。
简单实例 lock_set.c
int lock_set(int fd, int type)
{
struct flock old_lock, lock;
//初始化锁
lock.l_whence = SEEK_SET; //从文件头开始就上锁
lock.l_start = 0;
lock.l_len = 0;
lock.l_pid = -1;
lock.l_type = type;
fcntl(fd, F_GETLK, &lock); //得到锁的状态,赋值给lock中的l_type
if( lock.l_type != F_UNLCK) //是否上锁,上锁则进入判断
{
if(lock.l_type == F_RDLCK) //是不是读锁
{
printf("Read lock already set by %d\n", lock.l_pid);
}
else if(lock.l_type == F_WRLCK)//是不是写锁
{
printf("Write lock already set by %d\n",lock.l_pid);
}
}
lock.l_type = type;
if( (fcntl(fd, F_SETLKW, &lock)) < 0 ) //等待上锁
{
printf("Lock failed:type = %d \n", lock.l_type);
return -1;
}
switch(lock.l_type)
{
case F_RDLCK:
printf("Read lock set by %d\n", getpid());
break;
case F_WRLCK:
printf("Write lock set by %d\n",getpid());
break;
case F_UNLCK:
printf("Release lock by %d\n",getpid());
return 1;
break;
}
return 0;
}