HTTP文件服务器优化:获取文件大小

在优化Http文件服务器时,遇到了一些疑惑,就是怎么获取一个文件的大小?
目前我知道有两种方式,分别是:

  • 通过stat函数:
uint64_t getFileLength(const char *file){
    struct stat tFileStat;
    if (0 != stat(file, &tFileStat)) {
        //文件不存在
        return 0;
    }
    return tFileStat.st_size;
}
  • 通过ftell方式:
uint64_t getFileLength(FILE *fp){
    auto current = ftell(fp);
    fseek(fp,0L,SEEK_END); /* 定位到文件末尾 */
    auto end  = ftell(fp); /* 得到文件大小 */
    fseek(fp,current,SEEK_SET);
    return end - current;
}

前不久,我在修改ZLMediaKit的http文件服务器时,在实现mmap映射文件的同时,为了精简代码,把代码由stat方式改成了ftell方式,
但是后面不仅就收到了hls直播延时增加的反馈,我怀疑可能是这个改动导致的,所以今天特意测试了两者的性能对比,测试代码如下:

#include <sys/stat.h>
#include <cstdint>
#include <cstdio>
#include <sys/time.h>
#include <string>
using namespace std;
#define MAX_COUNT 1 * 1000000

uint64_t getFileLength(FILE *fp){
    auto current = ftell(fp);
    fseek(fp,0L,SEEK_END); /* 定位到文件末尾 */
    auto end  = ftell(fp); /* 得到文件大小 */
    fseek(fp,current,SEEK_SET);
    return end - current;
}

uint64_t getFileLength(const char *file){
    struct stat tFileStat;
    if (0 != stat(file, &tFileStat)) {
        //文件不存在
        return 0;
    }
    return tFileStat.st_size;
}


static inline uint64_t getCurrentMicrosecondOrigin() {
#if !defined(_WIN32)
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec * 1000000LL + tv.tv_usec;
#else
    return  std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
#endif
}

class TimePrinter {
public:
    TimePrinter(const string &str){
        _str = str;
        _start_time = getCurrentMicrosecondOrigin();
    }
    ~TimePrinter(){
        printf("%s占用时间:%d ms\n",_str.data(),(int)((getCurrentMicrosecondOrigin() - _start_time) / 1000));
    }

private:
    string _str;
    uint64_t _start_time;
};

int main(int argc, char *argv[]) {
    const char *file = "/Users/xzl/git/ZLMediaKit/release/mac/Debug/0ca86b00ccd5783194b13be6b0940c43.jpg";
    FILE *fp = fopen(file,"rb");
    {
        TimePrinter printer("stat方式获取文件大小:");
        for(int i = 0; i < MAX_COUNT ; ++i){
            getFileLength(file);
        }
    }

    {
        TimePrinter printer("ftell方式获取文件大小:");
        for(int i = 0; i < MAX_COUNT ; ++i){
            getFileLength(fp);
        }
    }

    return 0;
}


在我的电脑上,测试获取一个7KB的小文件大小,调用100万次,对比耗时如下:

stat方式获取文件大小:占用时间:1691 ms
ftell方式获取文件大小:占用时间:2590 ms

然后我有测试了一个600MB的大文件,调用100万次,对比耗时如下:

stat方式获取文件大小:占用时间:1682 ms
ftell方式获取文件大小:占用时间:2551 ms

我的电脑是2018款的256GB版本的macbook pro,我这里特意指出容量大小,是因为不同容量大小的ssd读写速度差别很大。
之后我又在一台linux虚拟机(宿主机是机械硬盘)上运行了同样的测试,结果也几乎一致。

从上述测试结果看,得出的结论是:

  • 文件的大小并不会影响速度,所以可以肯定的是,这两种方式都没有文件io的操作。
  • ftell和stat方式每次执行时间都很短,也没有拉开差距,fseek耗时多点应该是系统调用次数更多的原因。
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,144评论 1 32
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,548评论 0 17
  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 5,450评论 0 9
  • 今天是我们在安徽的最后一天,也是我最期待的一天,因为早就听说今天要去的宏村风景如画,非常的美,一路上我都非常的兴奋...
    马嘉玮阅读 269评论 0 1
  • 想当年我也是金戈铁马,气吞万里如虎,一言不合就出手,所以初中阶段经常是树敌无数,刀枪剑戟,斧钺钩叉都算挨过,身上...
    控卫阅读 851评论 0 0