文件读写操作的函数

时间:2023-02-07 09:58:31

笔记:

/*
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

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

当flags包含O_CREAT时,需要加参数mode。其他情况不用mode参数,加了也被忽略。

ssize_t read(int fd, void *buf, size_t count);
从fd中读取count大小的字节内容到buf中。返回读到的长度,出错返回-1。返回值可能比count小,这不被认为时错误,原因可能是文件本来就没有那么多东西读(已到达文件末尾,或者从pipe或terminal读),也可能是被信号打断了。

ssize_t write(int fd, const void *buf, size_t count);
从buf中写count大小的字节内容到fd。返回写入的长度(0表示没写进去任何东西),出错返回-1。实际写入字节数可能比count小,这不算错误,原因可能是因为磁盘中没有更多空间让你写了,或者文件大小已超过RLIMIT_FSIZE限制,或者写的过程中被信号打断了。

在写的过程中要注意文件是否被lseek了或文件是否有O_APPEND标记。

O_CREAT需要读写buffer对齐。
O_RDONLY, O_WRONLY, O_RDWR的值分别为012,因此,O_RDONLY|O_WRONLY和O_RDWR不一样哦。
open()可以创建设备文件,但creat()不行,可以用mknod。
O_NONBLOCK通常只用在你想打开文件但不想去读写,例如打开设备文件只进行ioctl操作。

用FILE指针打开和读写文件:
#include <stdio.h>

FILE *fopen(const char *path, const char *mode);
其中mode可以取:
r   读方式打开,文件pos在文件开头。
r+  读写方式打开,文件pos在文件开头。
w   写方式打开,将文件truncate0,如果文件不存在则新建。文件pos在文件开头。
w+  读写方式打开,将文件truncate0,如果文件不存在则新建。文件pos在文件开头。
a   追加方式打开,如果文件不存在则新建。文件pos在文件末尾(EOF)。
a+  读和追加方式打开,如果文件不存在则新建。读时文件pos在文件开头,写时pos在文件末尾(EOF)。
b   二进制方式,可加在上述mode的后面或mode组合的中间。在一些系统上,文本文件和二进制文件处理方式不同,想要读二进制就要加这个。

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);
注意fread不会区分end-of-file和error,返回值都会小于你本要写的长度,要通过feof()和ferror()做进一步判断。
int fseek(FILE *stream, long offset, int whence);//参数同lseek。第二个参数要传long型。成功返回0.
long ftell(FILE *stream);//获得当前pos。
void rewind(FILE *stream);//把文件流的pos指向0位置。同(void) fseek(stream, 0L, SEEK_SET);

char * readline (const char *prompt);
从命令行读取一行,以字符串形式给出结果。参数prompt通常为空,其他语言没有这个参数。
readline遇到换行符或EOF就返回,出错也返回(NULL)。返回值为读到的内容的指针(换行符被跳过,不返回)。
读的buffer是内部分配的,所以用完后记得手动释放掉。
读不到换行是阻塞住不返回的。
如果一行除了EOF没有内容,函数返回NULL。
*/

示例程序:


#include <stdio.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define TEST_FILE_NAME "./ftest.txt"

int main()
{
    int fd;
    unsigned char rwbuf[64];
    int readc, writec;
    off_t curoffset;

    //不加O_CREAT就不能新建
    fd = open(TEST_FILE_NAME, O_RDWR|O_CREAT, S_IRWXU); //O_RDONLY, O_WRONLY, O_CREAT, O_APPEND, O_SYNC, O_CLOEXEC,O_DIRECT
    if (fd == -1)
    {
        perror("open file failed");
        return 1;
    }
#if 1
    memset(rwbuf, 0, 64);
    readc = read(fd, rwbuf, 64);
    printf("%d, %s\n", readc, rwbuf); //不会因为'\0'或'\r''\n'停下来,并且它们也算一字节长度。
    //offset指向已经读的下一个字节

    curoffset = lseek(fd, 0, SEEK_CUR); //SEEK_SET, SEEK_END, SEEK_DATA, SEEK_HOLE
    printf("offset = %d\n", curoffset);

    lseek(fd, 12, SEEK_SET); //lseek64?
    writec = write(fd, "zhenfg", 6);
#else
    memset(rwbuf, 0, 64);
    readc = read(fd, rwbuf, 64);
    int i;
    for (i = 0; i < readc; i++) //可以读取二进制文件。不像fopen还要加"b"模式
    {
        printf("%02x ", rwbuf[i]);
    }
    printf("\n");
#endif
    close(fd);

    return 0;
}

读写文件时的判断示例:

#if 0
raw发包:
    while (send_left > 0/* && try_time--*/)
    {
        sent_bytes = send(sockfd, bufp, send_left, flags);
        if (0 > sent_bytes)
        {
            if (errno == EAGAIN || errno == EINTR)
            {
                continue;
            }
            else
            {
                return -1;
            }
        }
        if (0 == sent_bytes)
        {
            continue;
        }
        bufp += sent_bytes;
        send_left -= sent_bytes;
    }

读body:
while (判断) {
        ...
        ret = read(...);
        if (ret == 0) {
            return -1;
        } else if (ret == -1) {
            if (errno == EAGAIN) {
                read_deep--;
                if (read_deep <= 0)
                    return 0;
                else
                    continue;
            } else {
                return -1;
            }
        }
    }
#endif