open read write lseek写大文件的操作

头文件
#<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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值