以理智、安全、高效的方式复制文件

2023-12-31

我寻找一种复制文件(二进制或文本)的好方法。我已经写了几个示例,每个人都可以工作。但我想听听经验丰富的程序员的意见。

我缺少好的例子并寻找一种与 C++ 一起使用的方法。

ANSI-C-WAY

#include <iostream>
#include <cstdio>    // fopen, fclose, fread, fwrite, BUFSIZ
#include <ctime>
using namespace std;

int main() {
    clock_t start, end;
    start = clock();

    // BUFSIZE default is 8192 bytes
    // BUFSIZE of 1 means one chareter at time
    // good values should fit to blocksize, like 1024 or 4096
    // higher values reduce number of system calls
    // size_t BUFFER_SIZE = 4096;

    char buf[BUFSIZ];
    size_t size;

    FILE* source = fopen("from.ogv", "rb");
    FILE* dest = fopen("to.ogv", "wb");

    // clean and more secure
    // feof(FILE* stream) returns non-zero if the end of file indicator for stream is set

    while (size = fread(buf, 1, BUFSIZ, source)) {
        fwrite(buf, 1, size, dest);
    }

    fclose(source);
    fclose(dest);

    end = clock();

    cout << "CLOCKS_PER_SEC " << CLOCKS_PER_SEC << "\n";
    cout << "CPU-TIME START " << start << "\n";
    cout << "CPU-TIME END " << end << "\n";
    cout << "CPU-TIME END - START " << end - start << "\n";
    cout << "TIME(SEC) " << static_cast<double>(end - start) / CLOCKS_PER_SEC << "\n";

    return 0;
}

POSIX-WAY(K&R 在《C 编程语言》中使用了这个,更底层)

#include <iostream>
#include <fcntl.h>   // open
#include <unistd.h>  // read, write, close
#include <cstdio>    // BUFSIZ
#include <ctime>
using namespace std;

int main() {
    clock_t start, end;
    start = clock();

    // BUFSIZE defaults to 8192
    // BUFSIZE of 1 means one chareter at time
    // good values should fit to blocksize, like 1024 or 4096
    // higher values reduce number of system calls
    // size_t BUFFER_SIZE = 4096;

    char buf[BUFSIZ];
    size_t size;

    int source = open("from.ogv", O_RDONLY, 0);
    int dest = open("to.ogv", O_WRONLY | O_CREAT /*| O_TRUNC/**/, 0644);

    while ((size = read(source, buf, BUFSIZ)) > 0) {
        write(dest, buf, size);
    }

    close(source);
    close(dest);

    end = clock();

    cout << "CLOCKS_PER_SEC " << CLOCKS_PER_SEC << "\n";
    cout << "CPU-TIME START " << start << "\n";
    cout << "CPU-TIME END " << end << "\n";
    cout << "CPU-TIME END - START " << end - start << "\n";
    cout << "TIME(SEC) " << static_cast<double>(end - start) / CLOCKS_PER_SEC << "\n";

    return 0;
}

KISS-C++-Streambuffer-WAY

#include <iostream>
#include <fstream>
#include <ctime>
using namespace std;

int main() {
    clock_t start, end;
    start = clock();

    ifstream source("from.ogv", ios::binary);
    ofstream dest("to.ogv", ios::binary);

    dest << source.rdbuf();

    source.close();
    dest.close();

    end = clock();

    cout << "CLOCKS_PER_SEC " << CLOCKS_PER_SEC << "\n";
    cout << "CPU-TIME START " << start << "\n";
    cout << "CPU-TIME END " << end << "\n";
    cout << "CPU-TIME END - START " <<  end - start << "\n";
    cout << "TIME(SEC) " << static_cast<double>(end - start) / CLOCKS_PER_SEC << "\n";

    return 0;
}

复制算法-C++-WAY

#include <iostream>
#include <fstream>
#include <ctime>
#include <algorithm>
#include <iterator>
using namespace std;

int main() {
    clock_t start, end;
    start = clock();

    ifstream source("from.ogv", ios::binary);
    ofstream dest("to.ogv", ios::binary);

    istreambuf_iterator<char> begin_source(source);
    istreambuf_iterator<char> end_source;
    ostreambuf_iterator<char> begin_dest(dest); 
    copy(begin_source, end_source, begin_dest);

    source.close();
    dest.close();

    end = clock();

    cout << "CLOCKS_PER_SEC " << CLOCKS_PER_SEC << "\n";
    cout << "CPU-TIME START " << start << "\n";
    cout << "CPU-TIME END " << end << "\n";
    cout << "CPU-TIME END - START " <<  end - start << "\n";
    cout << "TIME(SEC) " << static_cast<double>(end - start) / CLOCKS_PER_SEC << "\n";

    return 0;
}

自己的缓冲区 C++ 方式

#include <iostream>
#include <fstream>
#include <ctime>
using namespace std;

int main() {
    clock_t start, end;
    start = clock();

    ifstream source("from.ogv", ios::binary);
    ofstream dest("to.ogv", ios::binary);

    // file size
    source.seekg(0, ios::end);
    ifstream::pos_type size = source.tellg();
    source.seekg(0);
    // allocate memory for buffer
    char* buffer = new char[size];

    // copy file    
    source.read(buffer, size);
    dest.write(buffer, size);

    // clean up
    delete[] buffer;
    source.close();
    dest.close();

    end = clock();

    cout << "CLOCKS_PER_SEC " << CLOCKS_PER_SEC << "\n";
    cout << "CPU-TIME START " << start << "\n";
    cout << "CPU-TIME END " << end << "\n";
    cout << "CPU-TIME END - START " <<  end - start << "\n";
    cout << "TIME(SEC) " << static_cast<double>(end - start) / CLOCKS_PER_SEC << "\n";

    return 0;
}

Linux-WAY// 需要内核 >= 2.6.33

#include <iostream>
#include <sys/sendfile.h>  // sendfile
#include <fcntl.h>         // open
#include <unistd.h>        // close
#include <sys/stat.h>      // fstat
#include <sys/types.h>     // fstat
#include <ctime>
using namespace std;

int main() {
    clock_t start, end;
    start = clock();

    int source = open("from.ogv", O_RDONLY, 0);
    int dest = open("to.ogv", O_WRONLY | O_CREAT /*| O_TRUNC/**/, 0644);

    // struct required, rationale: function stat() exists also
    struct stat stat_source;
    fstat(source, &stat_source);

    sendfile(dest, source, 0, stat_source.st_size);

    close(source);
    close(dest);

    end = clock();

    cout << "CLOCKS_PER_SEC " << CLOCKS_PER_SEC << "\n";
    cout << "CPU-TIME START " << start << "\n";
    cout << "CPU-TIME END " << end << "\n";
    cout << "CPU-TIME END - START " <<  end - start << "\n";
    cout << "TIME(SEC) " << static_cast<double>(end - start) / CLOCKS_PER_SEC << "\n";

    return 0;
}

环境

  • GNU/LINUX (Archlinux)
  • 内核3.3
  • GLIBC-2.15、LIBSTDC++ 4.7(GCC-LIBS)、GCC 4.7、Coreutils 8.16
  • 使用 RUNLEVEL 3(多用户、网络、终端、无 GUI)
  • INTEL SSD-Postville 80 GB,已满 50%
  • 复制 270 MB OGG 视频文件

重现步骤

 1. $ rm from.ogg
 2. $ reboot                           # kernel and filesystem buffers are in regular
 3. $ (time ./program) &>> report.txt  # executes program, redirects output of program and append to file
 4. $ sha256sum *.ogv                  # checksum
 5. $ rm to.ogg                        # remove copy, but no sync, kernel and fileystem buffers are used
 6. $ (time ./program) &>> report.txt  # executes program, redirects output of program and append to file

结果(使用的 CPU 时间)

Program  Description                 UNBUFFERED|BUFFERED
ANSI C   (fread/frwite)                 490,000|260,000  
POSIX    (K&R, read/write)              450,000|230,000  
FSTREAM  (KISS, Streambuffer)           500,000|270,000 
FSTREAM  (Algorithm, copy)              500,000|270,000
FSTREAM  (OWN-BUFFER)                   500,000|340,000  
SENDFILE (native LINUX, sendfile)       410,000|200,000  

文件大小不变。
sha256sum 打印相同的结果。
视频文件仍然可以播放。

问题

  • 您更喜欢哪种方法?
  • 您知道更好的解决方案吗?
  • 你看到我的代码有什么错误吗?
  • 您知道避免解决方案的原因吗?

  • FSTREAM(KISS、流缓冲区)
    我真的很喜欢这个,因为它真的很短而且简单。据我所知,运算符

Thanks

Update 1
我以这种方式更改了所有示例中的源,文件描述符的打开和关闭包含在测量中clock()。它们的源代码没有其他重大变化。结果没有改变!我也用过time仔细检查我的结果。

Update 2
ANSI C 示例已更改:条件while循环不再打电话feof()相反,我搬家了fread()进入状态。看起来,代码现在运行速度快了 10,000 个时钟。

测量改变:以前的结果总是被缓冲,因为我重复了旧的命令行rm to.ogv && 同步 && 时间 ./program每个程序几次。现在我为每个程序重新启动系统。未缓冲的结果是新的,并不令人意外。未缓冲的结果并没有真正改变。

如果我不删除旧副本,程序的反应会有所不同。覆盖现有文件bufferedPOSIX 和 SENDFILE 速度更快,所有其他程序都较慢。也许选项truncate or create对此行为有影响。但用相同的副本覆盖现有文件并不是现实世界的用例。

执行复制cp无缓冲需要 0.44 秒,缓冲需要 0.30 秒。所以cp比 POSIX 示例慢一点。对我来说看起来不错。

也许我还添加了样本和结果mmap() and copy_file()来自 boost::文件系统。

Update 3
我也将其放在博客页面上并对其进行了一些扩展。包括splice(),这是 Linux 内核的一个低级函数。也许接下来会出现更多使用 Java 的示例。http://www.ttyhoney.com/blog/?page_id=69 http://www.ttyhoney.com/blog/?page_id=69


以合理的方式复制文件:

#include <fstream>

int main()
{
    std::ifstream  src("from.ogv", std::ios::binary);
    std::ofstream  dst("to.ogv",   std::ios::binary);

    dst << src.rdbuf();
}

这本书读起来非常简单直观,值得额外付费。如果我们经常这样做,最好依靠操作系统对文件系统的调用。我相信boost在其文件系统类中有一个复制文件方法。

有一种与文件系统交互的 C 方法:

#include <copyfile.h>

int
copyfile(const char *from, const char *to, copyfile_state_t state, copyfile_flags_t flags);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

以理智、安全、高效的方式复制文件 的相关文章

  • 在 LINQ 查询中返回不带时间的日期

    我正在编写一个查询 我想计算按日期联系我们的呼叫中心的次数 看起来很简单 但由于联系日期字段是日期时间字段 我得到了时间 因此当我按联系日期 时间 分组时 每个联系日期实例的计数为 1 所以 我想只按日期分组 而不按时间分组 下面是我用来查
  • 属性对象什么时候创建?

    由于属性实际上只是附加到程序集的元数据 这是否意味着属性对象仅根据请求创建 例如当您调用 GetCustomAttributes 时 或者它们是在创建对象时创建的 或者 前两个的组合 在由于 CLR 的属性扫描而创建对象时创建 从 CLR
  • C++ 求二维数组每一行的最大值

    我已经设法用这个找到我的二维数组的每一行的最小值 void findLowest int A Cm int n int m int min A 0 0 for int i 0 i lt n i for int j 0 j lt m j if
  • 如何在C++中实现模板类协变?

    是否可以以这样一种方式实现类模板 如果模板参数相关 一个对象可以转换为另一个对象 这是一个展示这个想法的例子 当然它不会编译 struct Base struct Derived Base template
  • 为什么禁止在 constexpr 函数中使用 goto?

    C 14 对你能做什么和不能做什么有规则constexpr功能 其中一些 没有asm 没有静态变量 看起来相当合理 但标准也不允许goto in constexpr功能 即使它允许其他控制流机制 这种区别背后的原因是什么 我以为我们已经过去
  • 使用 C# 在 WinRT 中获取可用磁盘空间

    DllImport kernel32 dll SetLastError true static extern bool GetDiskFreeSpaceEx string lpDirectoryName out ulong lpFreeBy
  • .Net Core / 控制台应用程序 / 配置 / XML

    我第一次尝试使用新的 ConfigurationBuilder 和选项模式进入 Net Core 库 这里有很多很好的例子 https docs asp net en latest fundamentals configuration ht
  • Windows 窗体不会在调试模式下显示

    我最近升级到 VS 2012 我有一组在 VS 2010 中编码的 UI 测试 我试图在 VS 2012 中启动它们 我有一个 Windows 窗体 在开始时显示使用 AssemblyInitialize 属性运行测试 我使用此表单允许用户
  • 使用 LINQ 查找列表中特定类型的第一个元素

    使用 LINQ 和 C 在元素列表中查找特定类型的第一个项目的最短表示法是什么 var first yourCollection OfType
  • 线程、进程和 Application.Exit()

    我的应用程序由主消息循环 GUI 和线程 Task Factory 组成 在线程中我调用一些第三方应用程序var p new Process 但是当我调用Application Exit 在消息循环中 我可以看到在线程中启动的进程仍在内存中
  • 初始化变量的不同方式

    在 C 中初始化变量有多种方法 int z 3 与 int 相同z 3 Is int z z 3 same as int z z 3 您可以使用 int z z 3 Or just int z 3 Or int z 3 Or int z i
  • .NET 选项将视频文件流式传输为网络摄像头图像

    我有兴趣开发一个应用程序 它允许我从 xml 构建视频列表 包含视频标题 持续时间等 并将该列表作为我的网络摄像头流播放 这意味着 如果我要访问 ustream tv 或在实时通讯软件上激活我的网络摄像头 我的视频播放列表将注册为我的活动网
  • 将日期参数传递给对 MVC 操作的 ajax 调用的安全方法

    我有一个 MVC 操作 它的参数之一是DateTime如果我通过 17 07 2012 它会抛出一个异常 指出参数为空但不能有空值 但如果我通过01 07 2012它被解析为Jan 07 2012 我将日期传递给 ajax 调用DD MM
  • EPPlus Excel 更改单元格颜色

    我正在尝试将给定单元格的颜色设置为另一个单元格的颜色 该单元格已在模板中着色 但worksheet Cells row col Style Fill BackgroundColor似乎没有get财产 是否可以做到这一点 或者我是否必须在互联
  • 已过时 - OpenCV 的错误模式

    我正在使用 OpenCV 1 进行一些图像处理 并且对 cvSetErrMode 函数 它是 CxCore 的一部分 感到困惑 OpenCV 具有三种错误模式 叶 调用错误处理程序后 程序终止 Parent 程序没有终止 但错误处理程序被调
  • ListDictionary 类是否有通用替代方案?

    我正在查看一些示例代码 其中他们使用了ListDictionary对象来存储少量数据 大约 5 10 个对象左右 但这个数字可能会随着时间的推移而改变 我使用此类的唯一问题是 与我所做的其他所有事情不同 它不是通用的 这意味着 如果我在这里
  • 在 ASP.NET 中将事件冒泡为父级

    我已经说过 ASP NET 中的层次结构 page user control 1 user control 2 control 3 我想要做的是 当控件 3 它可以是任何类型的控件 我一般都想这样做 让用户用它做一些触发回发的事情时 它会向
  • 如何连接字符串和常量字符?

    我需要将 hello world 放入c中 我怎样才能做到这一点 string a hello const char b world const char C string a hello const char b world a b co
  • 为什么 strtok 会导致分段错误?

    为什么下面的代码给出了Seg 最后一行有问题吗 char m ReadName printf nRead String s n m Writes OK char token token strtok m 如前所述 读取字符串打印没有问题 但
  • 不同类型的指针可以互相分配吗?

    考虑到 T1 p1 T2 p2 我们可以将 p1 分配给 p2 或反之亦然吗 如果是这样 是否可以不使用强制转换来完成 或者我们必须使用强制转换 首先 让我们考虑不进行强制转换的分配 C 2018 6 5 16 1 1 列出了简单赋值的约束

随机推荐

  • 如何在 Asyncstorage 中设置多个值

    如何在 Asyncstorge 中设置多个值 因为我正在尝试设置token and user id 这些是服务器响应值 这就是响应的样子 json error 0 data User registered Successfully user
  • NSArray 基于密钥的 Tokenize

    我已经从服务器获取了数据并且传递的数据也填充了NSMutableArray after NSJSONSerialization 数组输出如下 NSArray jsonArray NSArray json NSLog Array jsonAr
  • 是否可以检测文件是否实际下载

    假设我有一个返回的控制器操作方法FileResult 是否可以检测文件是否被实际下载的完全交给客户 public ActionResult GetFile int id DownloadInfo data provider GetInfo
  • CUDA 中的块间同步

    我为这个问题搜索了一个月 我无法同步 CUDA 中的块 我读过很多关于atomicAdd 合作组等的文章 我决定使用一个全局数组 这样一个块就可以在全局数组的一个元素上写入 写入之后 块的线程将等待 即陷入 while 循环 直到所有块都写
  • 获取 Windows 窗体的大小

    我正在创建一个 Windows 窗体应用程序 如何捕获 Windows 窗体的大小 目前我的代码中有一些看起来像这样的东西 PictureBox display new PictureBox display Width 360 displa
  • 如何将 Json.NET 中缺失的属性反序列化为默认值?

    我有一个用 DataContract 和 DataMember 属性注释的类 部分成员被标记为DataMember IsRequired true 当我通过 Json NET 线路序列化实例时 所需的对象成员具有 null 值 那么它们的序
  • 请解释一下这个 Javascript 闭包练习 [重复]

    这个问题在这里已经有答案了 我是一个 javascript 菜鸟 试图理解下面的闭包练习 现在 我知道结果是 122 任何人都可以引导我一步步完成这个过程 什么被传递到什么 以便我能够理解闭包是如何工作的 var hidden myster
  • Android TTS 文本长度超过 4k 字符无法播放

    我在用TextToSpeech有时会播放一些长文本 我注意到从那以后Android 4 1 2如果文本长度超过 4000 个字符 则不会播放 我没有收到任何错误 但文本不会播放 直到现在我才能够重现这个Android 4 1 2 三星 Ga
  • maven - 当单元测试花费太长时间时构建失败

    我的项目中有很多用 JUnit 和 TestNG 编写的单元测试 构建过程基于带有surefire插件的maven 当至少一个单元测试花费太多秒时 是否有任何方法 插件使 Maven 构建失败 我知道有一些插件在 TeamCity Jenk
  • 在 Python 代码中参数化 MySQL IN 子句

    我正在看这个类似的问题 参数化 SQL IN 子句 https stackoverflow com questions 337704 parameterize an sql in clause但解决方案不是使用Python 所以我不得不提出
  • 使用委托的新实例取消注册事件

    EventHandler a new EventHandler control RegionChanged EventHandler b new EventHandler control RegionChanged if a b Conso
  • Python 2:集合和列表的“in”关键字的不同含义

    考虑这个片段 class SomeClass object def init self someattribute somevalue self someattribute someattribute def eq self other r
  • 创建条件图 python [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我只想绘制小于或等于某个数字 假设为 15 的值 我可以在数据帧的一列中找到这些值 如果这些值不小于或等于 15 我不想绘制它们 你能帮我找
  • django用户模型和自定义主键字段

    默认情况下 Django 在每个名为 的模型上创建一个主键字段 id 具有一种类型AutoField 在我的模型上 我将覆盖它以使用自定义UUIDField使用 作为主键primary key 属性 我也想要User模型中django co
  • 在CPU密集型任务上使用await关键字与Task.Wait()方法有什么区别?

    会是什么机械的之间的区别 async void LongIOBoundWorkWithSomeCPUBoundWorkAsWellAsync await Task Run CPUBoundWork Do IO bound work awai
  • 如何更改分类 x 轴的绘图顺序

    我得到了一个数据框 如下所示 df Time of Day Season value Day Shoulder 30 581606 Day Summer 25 865560 Day Winter 42 644530 Evening Shou
  • python,在 tkinter 中显示图像的函数?

    我想创建一个 tkinter 窗口并显示 lena 图片 我得到了一个可以工作的代码 但我不知道如何用它来创建一个函数 code import numpy import cv2 from Tkinter import from PIL im
  • HTML 选择下拉列表

    我想要一个使用选择 选项标签的下拉列表 但是当它第一次出现时我希望它有一个信息 例如 请选择一个名称 然后用户单击下拉列表并从中选择可用选项 我尝试将 请选择一个名称 作为选项 但用户将能够选择此 这不是我想要的 我需要使用 javascr
  • Xcode:运行 XC 单元测试时模块名称“”不是有效标识符

    尝试使用我设置的 CocoaPods 运行 XCTestSDWebImage 我只能看到这个错误 如下所示 有什么建议么 0 错误 模块名称 不是有效的标识符 命令 Applications Xcode8 3 1 app Contents
  • 以理智、安全、高效的方式复制文件

    我寻找一种复制文件 二进制或文本 的好方法 我已经写了几个示例 每个人都可以工作 但我想听听经验丰富的程序员的意见 我缺少好的例子并寻找一种与 C 一起使用的方法 ANSI C WAY include