头文件
#<sys/types.h>
#<unistd.h>
#include <fcntl.h>
#include <stdio.h>
三个系统接口,read,write,lseek,外加一个fysyn函数
准备阶段打开文件:
open打开文件
int fd = open(“filename”,O_RDWR),O_RDWR为文件打开模式,具体查询open()的man手册。
注:fd为文件文件描述符,使用<fcntl.h>中的open()获得
读文件read
read函数定义如下:
ssize_t read(int fd, void *buf, size_t count);
返回值:若成功则返回读到的字节数,若已到文件末尾则返回0,若出错则返回-1
fd: 文件描述符
buf: 读取数据缓存区
count: 要读取的字节数
read默认情况下是阻塞的,数据在不超过指定的长度的时候有多少读多少,没有数据就会一直等待。所以一般情况下,我们读取数据都需要采用循环读的方式读取数据,因为一次read 完毕不能保证读到我们需要长度的数据,read 完一次需要判断读到的数据长度再决定是否还需要再次读取。
但是需要注意:
read时fd中的数据如果小于要读取的数据,就会引起阻塞。(如果文件中数据,小于要读取的数据,或者已经到文件尾部,不会阻塞)
对一个管道的read只要管道中有数据,立马返回,不必等待达到所请求的字节数。
阻塞情况下
在阻塞条件下,read/recv/msgrcv的行为:
- 如果没有发现数据在网络缓冲中会一直等待;
- 当发现有数据的时候会把数据读到用户指定的缓冲区,但是如果这个时候读到的数据量比较少,比参数中指定的长度要小,read 并不会一直等待下去,而是立刻返回。
非阻塞情况下
在非阻塞的情况下,read 的行为
- 如果发现没有数据就直接返回,
- 如果发现有数据那么也是采用有多少读多少的进行处理.
所以read 完一次需要判断读到的数据长度再决定是否还需要再次读取。
写文件: write
ssize_t write(int fd, const void *buf, size_t nbyte);
fd:文件描述符;
buf:需要写入磁盘文件的内容,一般是一个指针指向一个缓冲空间;
nbyte:要写入文件指定的字节数;
返回值:写入文档的字节数(成功);-1(出错)
write函数把buf中nbyte写入文件描述符handle所指的文档,成功时返回写的字节数,错误时返回-1。错误情况写入到errno中。
附加说明:
- write()函数返回值一般无0,只有当如下情况发生时才会返回0:write(fp, p1+len, (strlen(p1)-len)中第三参数为0,此时write()什么也不做,只返回0。
- write()函数从buf写数据到fd中时,若buf中数据无法一次性读完,那么第二次读buf中数据时,其读位置指针(也就是第二个参数buf)不会自动移动,需要程序员编程控制,而不是简单的将buf首地址填入第二参数即可。如可按如下格式实现读位置移动:write(fp, p1+len, (strlen(p1)-len)。 这样write第二次循环时变会从p1+len处写数据到fp, 之后的也由此类推,直至(strlen(p1)-len变为0。
- 在write一次可以写的最大数据范围内(貌似是BUFSIZ ,8192),第三参数count大小最好为buf中数据的大小,以免出现错误。(经过笔者再次试验,write一次能够写入的并不只有8192这么多,笔者尝试一次写入81920000,结果也是可以,看来其一次最大写入数据并不是8192,但内核中确实有BUFSIZ这个参数,具体指什么还有待研究)
文件偏移: lseek
注意事项:
不是每个文件都能够设置偏移量,有些设备(或者说设备文件)不能使用lseek,linux系统不允许lseek()对tty设备进行操作,此项操作会使得lseek()范围错误代码ESPIPE,也有些文件如管道,FIFO或socket,无法设置偏移量,可以使用如下函数测试是否可以设置偏移量,如果返回-1,则表示不可以。
需要注意的事情是:lseek不能对网络套接字,管道,FIFO进行偏移操作。
off_t currpos;
currpos = lseek(fd, 0, SEEK_CUR);
使用lseek(int fd,int offset,int whence)可跳到指定文件位置读写
whence有三个标志符,
SEEK_SET :到offset指定的位置(距离文件开头offset位, 从文件头,开始偏移)(offset 只能是正数)
SEEK_CUR: 到现在的位置+offset (offset 可正可负,正是向后,负是向前)
SEEK_END: 到末尾+offset(从文件结尾)(offset 可正可负,正是向前,负是向后)
例如:lseek(fd,5,SEEK_END); 即转到文件末尾后五个字节处
下面的例子
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
typedef unsigned int uint32;
typedef unsigned short uint16;
typedef unsigned char uint8;
typedef signed int int32;
typedef signed short int16;
typedef signed char int8;
#define CONFIG_FILE "config.txt"
int main (int argc, char *argv[])
{
int fd = 0;
int byte_num = 0;
int offset_result = 0;
int i = 0;
uint8 buf[100] = {0};
uint8 append_buf[20] = {0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,'\n','\0'};
for(i=0; i< 98; i++)
{
buf[i] = i + 0x15;
}
buf[98] = '\n';
fd = open(CONFIG_FILE, O_RDWR | O_CREAT, 0764);
if(fd < 0)
{
printf("open error\n");
close(fd);
return -1;
}
byte_num = write(fd,buf, sizeof(buf));
if(byte_num < 0)
{
printf("write error\n");
close(fd);
return -1;
}
else if(byte_num <= 100)
{
printf("write num %d\n", byte_num);
}
printf("\nwill sleep 20s \n");
sleep(20);
offset_result = lseek(fd, 0, SEEK_END);
if(offset_result < 0)
{
printf("lseek error\n");
close(fd);
return -1;
}
else
{
byte_num = write(fd, append_buf, sizeof(append_buf));
if(byte_num < 0)
{
printf("append write file error\n");
close(fd);
return -1;
}
else
{
printf("write bytes %d\n", byte_num);
close(fd);
}
}
printf("successed\n");
return 0;
}
加上同步IO操作的fysyn函数
uint8_t p_file = NULL;
int number_code = 0;
int total_number_code = 0;
int file_length = 0;
int fd = 0;
int num_written = 0;
int once_written = 0;
int written_times = 0;
if(number_code == 0)
{
/*create file: tmp/ap_data_config.conf, O_NONBLOCK, non blocking*/
fd = open(FILE_NAME, O_RDWR | O_CREAT |O_NONBLOCK, 0764);
if(fd < 0)
{
debug_msg("open create file failed. number_code = %d", number_code);
close(fd);
return FRAME_OPEN_FILE_ERROR;
}
/*non blocking, write the file circularly until all data is written to the file*/
p_file = file_buf;
num_written = file_length;
while(num_written > 0)
{
once_written = write(fd, p_file, (size_t)num_written);
if(once_written > 0)
{
p_file += once_written;
num_written -= once_written;
written_times++;
}
}
fsync(fd);
close(fd);
debug_msg("write file success. num_written %d, written_times %d", num_written,written_times);
}
else if(number_code <= total_number_code)
{
/*append write file, O_NONBLOCK, non blocking*/
fd = open(FILE_NAME, O_RDWR|O_NONBLOCK, 0764);
if(fd < 0)
{
debug_msg("open file failed. number_code= %d", number_code);
close(fd);
return OPEN_FILE_ERROR;
}
/*offset*/
offset_result = lseek(fd, 0, SEEK_END);
if(offset_result < 0)
{
debug_msg("offset fd to file end failed. offset_result = %d", offset_result);
close(fd);
return OPEN_FILE_ERROR;
}
/*non blocking, write the file circularly until all data is written to the file*/
p_file = file_buf;
num_written = file_length;
while(num_written > 0)
{
once_written = write(fd, p_file, (size_t)num_written);
if(once_written > 0)
{
p_file += once_written;
num_written -= once_written;
written_times++;
}
}
fsync(fd);
close(fd);
debug_msg("write file number_code %d, written_times %d", number_code, written_times);
}
else
{
debug_msg("number_code %d > total_number_code %d", number_code, total_number_code);
return ANALYSIS_ERROR;
}