linux c怎么实现从文件的最后一行一行向前读文件

linux c怎么实现从文件的最后一行一行向前读文件,第1张

下面的例子使用mmap读最后20行(假设最后20行不会超过1024字节)

/*-

* Copyright (C), 1988-2014, mymtom

*

* vi:set ts=4 sw=4:

*/

#ifndef lint

static const char rcsid[] = "$Id$"

#endif /* not lint */

/**

* @filelast20.c

* @brief

*/

#include <sys/types.h>

#include <sys/stat.h>

#include <sys/mman.h>

#include <unistd.h>

#include <limits.h>

#include <stdio.h>

#include <string.h>

char *memchrr(const void *v1, const char *v2, int c)

{

char *s1, *s2

char *p

s1 = (char *)v1

s2 = (char *)v2

for (p = s2p >= s1--p) {

if (*p == c)

return p

}

return NULL

}

#define READSIZE1024

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

{

int ret

FILE *fp

char *addr

size_t len

int prot

int flags

int fd

off_t off

off_t rem

long pagesize

struct stat buf

pagesize = sysconf(_SC_PAGESIZE)

fp = fopen("last20.c", "rb")

fd = fileno(fp)

ret = fstat(fd, &buf)

if (buf.st_size <= READSIZE || buf.st_size <= pagesize) {

off = 0

len = buf.st_size

} else {

off = buf.st_size - READSIZE

rem = off % pagesize

off = off - rem

len = READSIZE + rem

}

/*

printf("size=%d READSIZE=%d off=%d len=%d\n",

(int)buf.st_size, (int)READSIZE, (int)off, (int)len)

*/

prot = PROT_READ

flags = MAP_PRIVATE

addr = mmap(NULL, len, prot, flags, fd, off)

fclose(fp)

{

int i, n

char *head, *tail

size_t size

char line[1024]

tail = addr + len - 1

n = 20

for (i = 0i <n++i) {

head = memchrr(addr, tail - 1, '\n')

if (head == NULL) {

size = tail - addr

memcpy(line, addr, size)

line[size] = '\0'

} else {

size = tail - head - 1

memcpy(line, head + 1, size)

line[size] = '\0'

tail = head

}

printf("%s\n", line)

if (head == NULL) {

break

}

}

}

munmap(addr, len)

return 0

}

运行结果为:

./last20 | tac | cat -n

line[size] = '\0'

} else {

size = tail - head - 1

memcpy(line, head + 1, size)

line[size] = '\0'

tail = head

}

printf("%s\n", line)

if (head == NULL) {

break

}

}

}

munmap(addr, len)

return 0

}

1,首先需要了解cp的原理。

2,可以参考cp的源码去了解其原理

3,cp命令的源码可以在linux内核中找到。

4,或者下载busybox其中也会有cp的源码

只有了解其原理之后才能谈如何实现。参考代码如下:

#include <stdio.h>

#include <stdlib.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <fcntl.h>

#include <errno.h>

#include <unistd.h>

#include <string.h>

#define BUF_SIZE 1024

#define PATH_LEN 128

void my_err(char *err_string, int line )

{

    fprintf(stderr,"line:%d ",line)

    perror(err_string) 

    exit(1)

}

void copy_data(const int frd,const int fwd)

{

    int read_len = 0, write_len = 0

    unsigned char buf[BUF_SIZE], *p_buf

    while ( (read_len = read(frd,buf,BUF_SIZE)) ) {

        

        if (-1 == read_len) {

            my_err("Read error", __LINE__)

        }

        else if (read_len > 0) { //把读取部分写入目标文件

            p_buf = buf

            while ( (write_len = write(fwd,p_buf,read_len)) ) {

                if(write_len == read_len) {

                    break

                }

                else if (write_len > 0) { //只写入部分

                    p_buf += write_len

                    read_len -= write_len

                }

                else if(-1 == write_len) {

                    my_err("Write error", __LINE__)

                }

            }

            if (-1 == write_len) break

        }

    }

}

int main(int argc, char **argv) 

{

    

    int frd, fwd //读写文件描述符

    int len = 0

    char *pSrc, *pDes //分别指向源文件路径和目标文件路径

    struct stat src_st,des_st

    

    if (argc < 3) {

        printf("用法 ./MyCp <源文件路径> <目标文件路径>\n")

        my_err("arguments error ", __LINE__)

    }

    

    frd = open(argv[1],O_RDONLY)

    if (frd == -1) {

        my_err("Can not opne file", __LINE__)

    }

    if (fstat(frd,&src_st) == -1) {

        my_err("stat error",__LINE__)

    }

    /*检查源文件路径是否是目录*/

    if (S_ISDIR(src_st.st_mode)) {

        my_err("略过目录",__LINE__)

    }

    

    pDes = argv[2]

    stat(argv[2],&des_st)

    if (S_ISDIR(des_st.st_mode)) { //目标路径是目录,则使用源文件的文件名

        

        len = strlen(argv[1])

        pSrc = argv[1] + (len-1) //指向最后一个字符

        /*先找出源文件的文件名*/

        while (pSrc >= argv[1] && *pSrc != '/') {

            pSrc--

        }

        pSrc++//指向源文件名

        

        len = strlen(argv[2]) 

        // . 表示复制到当前工作目录

        if (1 == len && '.' == *(argv[2])) {

            len = 0 //没有申请空间,后面就不用释放

            pDes = pSrc

        }

        else { //复制到某目录下,使用源文件名

            pDes = (char *)malloc(sizeof(char)*PATH_LEN)

            if (NULL == pDes) {

                my_err("malloc error ", __LINE__)

            }

            

            strcpy(pDes,argv[2])

        

            if ( *(pDes+(len-1)) != '/' ) { //目录缺少最后的'/',则补上’/‘

                strcat(pDes,"/")

            }

            strcat(pDes+len,pSrc)

        }

    }

    

    /* 打开目标文件, 使权限与源文件相同*/ 

    fwd = open(pDes,O_WRONLY | O_CREAT | O_TRUNC,src_st.st_mode)

    if (fwd == -1) {

        my_err("Can not creat file", __LINE__)

    }

    copy_data(frd,fwd)

    //puts("end of copy")

    if (len > 0 && pDes != NULL)

        free(pDes)

    

    close(frd)

    close(fwd)

    return 0

}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/5929646.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-03-08
下一篇 2023-03-08

发表评论

登录后才能评论

评论列表(0条)

保存