欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C语言学习第015课——文件操作(二)

程序员文章站 2022-03-09 16:15:43
...

上一篇博文最后的内容,使用1024字节 也就是1KB的缓冲区,
去拷贝了20M的文件,循环次数有点多,可以通过修改SIZE的值,改成1024*1024或者8*1024*1024也就是8M,循环次数就小多了
遇到大文件,就用8M的缓冲区,遇到小文件就用1KB的缓冲区就行
那么如何获取到文件的大小呢?

获取文件状态

#include <sys/types.h>
#include <sys/stat.h>
int stat(const char *path, struct stat *buf);
功能:获取文件状态信息
参数:
path:文件名
buf:保存文件信息的结构体
返回值:
成功:0
失败-1

struct stat {
	dev_t         st_dev;         文件的设备编号
	ino_t         st_ino;         节点
	mode_t        st_mode;   	  文件的类型和存取的权限
	nlink_t       st_nlink;       连到该文件的硬连接数目,刚建立的文件值为1
	uid_t         st_uid;         用户ID
	gid_t         st_gid;         组ID
	dev_t         st_rdev;        (设备类型)若此文件为设备文件,则为其设备编号
	off_t         st_size;        文件字节数(文件大小)
	unsigned long st_blksize;     块大小(文件系统的I/O 缓冲区大小)
	unsigned long st_blocks;      块数
	time_t        st_atime;       最后一次访问时间
	time_t        st_mtime;      最后一次修改时间
	time_t        st_ctime;      最后一次改变时间(指属性)
};

我们需要使用到的是st_size,简单的使用一下stat函数

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>

int main(void){
    struct stat st;
    stat("hello.txt",&st);
    
    printf("%d\n",(int)st.st_size);
}

运行结果:
C语言学习第015课——文件操作(二)
将stat函数使用到文件拷贝中,如果文件大于8M,就开辟8M的缓冲区进行拷贝,如果文件小于8M,就开辟文件大小的缓冲区进行拷贝

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>

#define SIZE 8*1024*1024


int main(int argc,char* argv[]){
    FILE* fp1 = fopen(argv[1],"rb");
    FILE* fp2 = fopen(argv[2],"wb");
    if(!fp1 || !fp2){
        printf("操作失败\n");
        return -1;
    }
    if(argc<3){
        printf("缺少参数\n");
        return -2;
    }
    //开始读写
    struct stat st;					获取文件状态,放入到st结构体中
    stat(argv[1],&st);
    char* ptemp = NULL;
    int size = 0;
    if(st.st_size>SIZE){			根据文件大小,分配不同大小的内存空间
        ptemp = (char*)malloc(sizeof(char)*SIZE);
        size = SIZE;				不同大小的内存空间相应的函数参数也会发生改变
    }else{
        ptemp = (char*)malloc(sizeof(char)*st.st_size+10);
        size = st.st_size+10;			小文件多预留10个字节的缓冲区,为了安全起见
    }
    printf("开辟的缓冲区大小为%d字节\n",size);
    int count = 0;
    while(!feof(fp1)){
        memset(ptemp,0,size);
        count = fread(ptemp,1,size,fp1);
        fwrite(ptemp,1,count,fp2);
    }
    free(ptemp);
    fclose(fp1);
    fclose(fp2);
    printf("拷贝成功\n");
    return 0;
}

执行命令
C语言学习第015课——文件操作(二)

运行结果
C语言学习第015课——文件操作(二)
C语言学习第015课——文件操作(二)

文件的随机读写

#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
功能:移动文件流(文件光标)的读写位置。
参数:
	stream:已经打开的文件指针
	offset:根据whence来移动的位移数(偏移量),可以是正数,也可以负数,如果正数,则相对于whence往右移动,如果是负数,则相对于whence往左移动。如果向前移动的字节数超过了文件开头则出错返回,如果向后移动的字节数超过了文件末尾,再次写入时将增大文件尺寸。
	whence:其取值如下:
		SEEK_SET:从文件开头移动offset个字节
		SEEK_CUR:从当前位置移动offset个字节
		SEEK_END:从文件末尾移动offset个字节
返回值:
	成功:0
	失败:-1

以下代码,是使用fgets读取文本文件两行数据

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(void){
    FILE* fp = fopen("hello.txt","r");
    char str[30];
    memset(str,0,30);
    fgets(str,30,fp);
    printf("%s",str);

    memset(str,0,30);
    fgets(str,30,fp);
    printf("%s",str);

    return 0;
}

现在想读完第二行之后,再读一次第二行,使用fseek函数实现,
我们知道,fseek函数是给光标进行偏移的,第二行内容“打不过我吧”5个汉字加一个\r和\n(Windows平台下的文件换行都是\r\n,Linux不是)
总共就是12个字节,所以使用fseek函数,先从当前位置往前偏移上12个字节试试

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(void){
    FILE* fp = fopen("hello.txt","r");
    char str[30];
    memset(str,0,30);
    fgets(str,30,fp);
    printf("%s",str);

    memset(str,0,30);
    fgets(str,30,fp);
    printf("%s",str);

    fseek(fp,-12,SEEK_CUR);			从当前光标位置,向左偏移12个字节 向右偏移时 使用正数
    memset(str,0,30);
    fgets(str,30,fp);
    printf("%s",str);
    return 0;
}

运行结果:
C语言学习第015课——文件操作(二)