Sao chép một tập tin một cách lành mạnh, an toàn và hiệu quả


305

Tôi tìm kiếm một cách tốt để sao chép một tập tin (nhị phân hoặc văn bản). Tôi đã viết một số mẫu, mọi người đều làm việc. Nhưng tôi muốn nghe ý kiến ​​của các lập trình viên dày dạn kinh nghiệm.

Tôi thiếu các ví dụ hay và tìm kiếm cách làm việc với C ++.

AN-C-CÁCH

#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 sử dụng điều này trong "Ngôn ngữ lập trình C", mức độ thấp hơn)

#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-CÁCH

#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;
}

SAO CHÉP-ALGORITHM-C ++ - CÁCH

#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;
}

RIÊNG-BUFFER-C ++ - CÁCH

#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 // yêu cầu kernel> = 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;
}

Môi trường

  • GNU / LINUX (Archlinux)
  • Hạt nhân 3.3
  • GLIBC-2.15, LIBSTDC ++ 4.7 (GCC-LIBS), GCC 4.7, Coreutils 8.16
  • Sử dụng RUNLEVEL 3 (Multiuser, Network, Terminal, không có GUI)
  • INTEL SSD-Postville 80 GB, chiếm tới 50%
  • Sao chép một tập tin OGG-VIDEO-FILE 270 MB

Các bước để tái sản xuất

 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

Kết quả (CPU TIME được sử dụng)

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  

Kích thước tập tin không thay đổi.
sha256sum in kết quả tương tự.
Các tập tin video vẫn có thể chơi được.

Câu hỏi

  • Bạn thích phương pháp nào?
  • Bạn có biết giải pháp tốt hơn?
  • Bạn có thấy bất kỳ sai lầm trong mã của tôi?
  • Bạn có biết một lý do để tránh một giải pháp?

  • FSTREAM (KISS, Streambuffer)
    Tôi thực sự thích cái này, vì nó thực sự ngắn và đơn giản. Theo như tôi biết thì toán tử << bị quá tải cho rdbuf () và không chuyển đổi bất cứ thứ gì. Chính xác?

Cảm ơn

Cập nhật 1
Tôi đã thay đổi nguồn trong tất cả các mẫu theo cách đó, rằng mở và đóng của bộ mô tả tệp được bao gồm trong phép đo đồng hồ () . Chúng không có thay đổi đáng kể nào khác trong mã nguồn. Kết quả không thay đổi! Tôi cũng đã sử dụng thời gian để kiểm tra lại kết quả của mình.

Cập nhật 2
mẫu ANSI C đã thay đổi: Điều kiện của vòng lặp while không gọi bất kỳ lệnh nào nữa () thay vào đó tôi chuyển fread () vào điều kiện. Có vẻ như, mã chạy bây giờ 10.000 đồng hồ nhanh hơn.

Phép đo đã thay đổi: Các kết quả trước đây luôn được đệm, bởi vì tôi đã lặp lại dòng lệnh cũ rm to.ogv && sync && time ./program cho mỗi chương trình một vài lần. Bây giờ tôi khởi động lại hệ thống cho mọi chương trình. Các kết quả không có bộ đệm là mới và không có gì bất ngờ. Các kết quả không có bộ đệm đã không thực sự thay đổi.

Nếu tôi không xóa bản sao cũ, các chương trình sẽ phản ứng khác nhau. Ghi đè một tệp hiện có được đệm nhanh hơn với POSIX và SENDFILE, tất cả các chương trình khác đều chậm hơn. Có thể các tùy chọn cắt bớt hoặc tạo ra có tác động đến hành vi này. Nhưng ghi đè các tệp hiện có cùng một bản sao không phải là trường hợp sử dụng trong thế giới thực.

Thực hiện sao chép với cp mất 0,44 giây không có bộ đệm và 0,30 giây được đệm. Vì vậy, cp chậm hơn một chút so với mẫu POSIX. Có vẻ tốt cho tôi.

Có lẽ tôi cũng thêm các mẫu và kết quả của mmap ()copy_file()từ boost :: filesystem.

Cập nhật 3
Tôi cũng đã đặt nó trên một trang blog và mở rộng nó ra một chút. Bao gồm splice () , là một hàm cấp thấp từ nhân Linux. Có thể nhiều mẫu với Java sẽ làm theo. http://www.ttyhoney.com/blog/?page_id=69


5
fstreamchắc chắn là một lựa chọn tốt cho các hoạt động tập tin.
chris


29
Bạn đã quên cách lười biếng: system ("cp from.ogv to.ogv");
fbafelipe

3
#include <copyfile.h> copyfile(const char *from, const char *to, copyfile_state_t state, copyfile_flags_t flags);
Martin York

3
Xin lỗi vì đã sứt mẻ quá muộn, nhưng tôi sẽ mô tả không ai trong số này là 'an toàn', vì họ không có bất kỳ xử lý lỗi nào.
Richard Kettlewell

Câu trả lời:


259

Sao chép một tập tin theo cách lành mạnh:

#include <fstream>

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

    dst << src.rdbuf();
}

Điều này rất đơn giản và trực quan để đọc nó là giá trị chi phí thêm. Nếu chúng ta đã làm điều đó rất nhiều, tốt hơn là nên quay lại các cuộc gọi hệ điều hành đến hệ thống tệp. Tôi chắc chắn boostcó một phương thức tập tin sao chép trong lớp hệ thống tập tin của nó.

Có một phương thức C để tương tác với hệ thống tệp:

#include <copyfile.h>

int
copyfile(const char *from, const char *to, copyfile_state_t state, copyfile_flags_t flags);

29
copyfilekhông phải là hàng xách tay; Tôi nghĩ nó đặc trưng cho Mac OS X. Nó chắc chắn không tồn tại trên Linux. boost::filesystem::copy_filecó lẽ là cách di động nhất để sao chép tệp qua hệ thống tệp gốc.
Mike Seymour

4
@MikeSeymour: copyfile () dường như là một phần mở rộng BSD.
Martin York

10
@ duedl0r: Không. Đối tượng có hàm hủy. Hàm hủy cho các luồng tự động gọi close (). codereview.stackexchange.com/q/540/507
Martin York

11
@ duedl0r: Vâng. Nhưng điều đó giống như nói "nếu mặt trời lặn". Bạn có thể chạy rất nhanh về phía tây và bạn có thể làm cho ngày của bạn dài hơn một chút nhưng mặt trời sẽ lặn. Trừ khi bạn có lỗi và bộ nhớ bị rò rỉ (nó sẽ vượt ra khỏi phạm vi). Nhưng vì không có quản lý bộ nhớ động ở đây nên không thể có rò rỉ và chúng sẽ vượt ra khỏi phạm vi (giống như mặt trời sẽ lặn).
Martin York

6
Sau đó, chỉ cần bọc nó trong một khối phạm vi {}
paulm

62

Với C ++ 17, cách tiêu chuẩn để sao chép tệp sẽ bao gồm <filesystem>tiêu đề và sử dụng:

bool copy_file( const std::filesystem::path& from,
                const std::filesystem::path& to);

bool copy_file( const std::filesystem::path& from,
                const std::filesystem::path& to,
                std::filesystem::copy_options options);

Hình thức đầu tiên tương đương với hình thức thứ hai copy_options::noneđược sử dụng làm tùy chọn (xem thêm copy_file).

Các filesystemthư viện ban đầu được phát triển như là boost.filesystemvà cuối cùng sáp nhập vào ISO C ++ như C ++ 17.


2
Tại sao không có một hàm duy nhất với một đối số mặc định, như thế bool copy_file( const std::filesystem::path& from, const std::filesystem::path& to, std::filesystem::copy_options options = std::filesystem::copy_options::none);nào?
Jepessen

2
@Jepessen Tôi không chắc về điều này. Có lẽ nó không thực sự quan trọng .
manlio

@Jepessen trong thư viện chuẩn, mã sạch là tối quan trọng. Có quá tải (trái ngược với một chức năng với các tham số mặc định) làm cho ý định của lập trình viên rõ ràng hơn.
Marc.2377

@Peter Đây có lẽ là câu trả lời được chấp nhận cho rằng C ++ 17 có sẵn.
Martin York

21

Quá nhiều!

Bộ đệm theo cách "ANSI C" là dự phòng, vì a FILEđã được đệm. (Kích thước của bộ đệm nội bộ này là những gì BUFSIZthực sự xác định.)

"OWN-BUFFER-C ++ - WAY" sẽ chậm khi nó đi qua fstream, điều này thực hiện rất nhiều việc gửi ảo và một lần nữa duy trì bộ đệm nội bộ hoặc từng đối tượng luồng. ("COPY-ALGORITHM-C ++ - CÁCH" không chịu điều này, vì streambuf_iteratorlớp bỏ qua lớp luồng.)

Tôi thích "COPY-ALGORITHM-C ++ - CÁCH", nhưng không xây dựng một fstream, chỉ tạo các std::filebuftrường hợp trần khi không cần định dạng thực tế.

Đối với hiệu suất thô, bạn không thể đánh bại các mô tả tệp POSIX. Nó xấu nhưng di động và nhanh chóng trên mọi nền tảng.

Cách Linux dường như cực kỳ nhanh - có lẽ HĐH cho phép chức năng quay trở lại trước khi I / O kết thúc? Trong mọi trường hợp, điều đó không đủ khả năng di động cho nhiều ứng dụng.

EDIT : Ah, "Linux bản địa" có thể được cải thiện hiệu suất bằng cách xen kẽ các lần đọc và ghi với I / O không đồng bộ. Để các lệnh chồng chất có thể giúp trình điều khiển đĩa quyết định khi nào là tốt nhất để tìm kiếm. Bạn có thể thử Boost Asio hoặc pthreads để so sánh. Đối với "không thể đánh bại các mô tả tệp POSIX" thì điều đó đúng nếu bạn làm bất cứ điều gì với dữ liệu, không chỉ sao chép một cách mù quáng.


ANSI C: Nhưng tôi phải cung cấp cho hàm fread / fwrite một kích thước? pubs.opengroup.org/onlinepub/9699919799/toc.htm
Peter

@PeterWeber Vâng, vâng, đúng là BUFSIZ có giá trị tương đương với bất kỳ thứ gì, và có thể sẽ tăng tốc mọi thứ lên tương ứng với một hoặc "chỉ một vài" ký tự một lần. Dù sao, phép đo hiệu suất cho thấy đó không phải là phương pháp tốt nhất trong mọi trường hợp.
Potatoswatter

1
Tôi chưa hiểu sâu về vấn đề này, vì vậy tôi nên cẩn thận với các giả định và ý kiến. Linux-Way chạy trong Kernelspace afaik. Điều này có nên tránh chuyển đổi bối cảnh chậm giữa Kernelspace và Userspace? Ngày mai tôi sẽ xem lại trang chủ của sendfile. Cách đây một thời gian, Linus Torvalds nói rằng ông không thích Userspace-Filesystems cho các công việc nặng. Có lẽ sendfile là một ví dụ tích cực cho quan điểm của mình?
Peter

5
" sendfile()sao chép dữ liệu giữa một bộ mô tả tệp và một tệp khác. Bởi vì việc sao chép này được thực hiện trong kernel, sendfile()hiệu quả hơn so với sự kết hợp read(2)write(2), sẽ yêu cầu chuyển dữ liệu đến và từ không gian người dùng.": kernel.org/doc/man-pages /online/pages/man2/sendfile.2.html
Max Lybbert

1
Bạn có thể gửi một ví dụ về việc sử dụng filebufcác đối tượng thô ?
Kerrek SB

14

Tôi muốn đưa ra một lưu ý rất quan trọng rằng phương thức LINUX sử dụng sendfile () có một vấn đề lớn ở chỗ nó không thể sao chép các tệp có kích thước lớn hơn 2GB! Tôi đã thực hiện nó theo câu hỏi này và đã gặp phải sự cố vì tôi đang sử dụng nó để sao chép các tệp HDF5 có kích thước nhiều GB.

http://man7.org/linux/man-pages/man2/sendfile.2.html

sendfile () sẽ chuyển tối đa 0x7ffff000 (2.147.479.552) byte, trả về số byte thực sự được chuyển. (Điều này đúng trên cả hệ thống 32 bit và 64 bit.)


1
sendfile64 () có vấn đề tương tự không?
Graywolf

1
@Paladin Có vẻ như sendfile64 đã được phát triển để vượt qua giới hạn này. Từ trang man: "" "Cuộc gọi hệ thống sendfile () ban đầu của Linux không được thiết kế để xử lý các tập tin lớn. Do đó, Linux 2.4 đã thêm sendfile64 (), với loại rộng hơn cho đối số bù. minh bạch đối phó với sự khác biệt của hạt nhân. "" "
rveale

sendfile64 có cùng một vấn đề . Tuy nhiên, việc sử dụng loại bù off64_tcho phép người ta sử dụng một vòng lặp để sao chép các tệp lớn như trong câu trả lời cho câu hỏi được liên kết.
pcworld

đây là wirtten in man: 'Lưu ý rằng một cuộc gọi thành công tới sendfile () có thể ghi ít byte hơn yêu cầu; người gọi nên chuẩn bị thử lại cuộc gọi nếu có byte chưa gửi. ' sendfile hoặc sendfile64 có thể yêu cầu được gọi trong vòng lặp cho đến khi sao chép đầy đủ.
philippe lhardy

2

Qt có một phương pháp để sao chép tập tin:

#include <QFile>
QFile::copy("originalFile.example","copiedFile.example");

Lưu ý rằng để sử dụng điều này, bạn phải cài đặt Qt (hướng dẫn tại đây ) và đưa nó vào dự án của bạn (nếu bạn đang sử dụng Windows và bạn không phải là quản trị viên, bạn có thể tải xuống Qt tại đây ). Cũng xem câu trả lời này .


1
QFile::copybị chậm một cách lố bịch do bộ đệm 4k của nó .
Nicolas Holthaus

1
Sự chậm chạp đã được sửa trong các phiên bản mới hơn của Qt. Tôi đang sử dụng 5.9.2và tốc độ ngang bằng với việc thực hiện riêng. Btw. nhìn vào mã nguồn, Qt dường như thực sự gọi việc thực hiện riêng.
VK

1

Đối với những người thích boost:

boost::filesystem::path mySourcePath("foo.bar");
boost::filesystem::path myTargetPath("bar.foo");

// Variant 1: Overwrite existing
boost::filesystem::copy_file(mySourcePath, myTargetPath, boost::filesystem::copy_option::overwrite_if_exists);

// Variant 2: Fail if exists
boost::filesystem::copy_file(mySourcePath, myTargetPath, boost::filesystem::copy_option::fail_if_exists);

Lưu ý rằng đường dẫn boost :: filesystem :: cũng có sẵn dưới dạng wpath cho Unicode. Và bạn cũng có thể sử dụng

using namespace boost::filesystem

nếu bạn không thích những cái tên dài


Thư viện hệ thống tập tin của Boost là một trong những trường hợp ngoại lệ yêu cầu nó phải được biên dịch. Chỉ cần FYI!
SimonC

0

Tôi không chắc chắn "cách tốt" của việc sao chép tệp là gì, nhưng giả sử "tốt" có nghĩa là "nhanh", tôi có thể mở rộng chủ đề một chút.

Các hệ điều hành hiện tại từ lâu đã được tối ưu hóa để đối phó với việc chạy bản sao tập tin mill. Không có chút thông minh nào của mã sẽ đánh bại điều đó. Có thể một số biến thể của các kỹ thuật sao chép của bạn sẽ chứng minh nhanh hơn trong một số tình huống thử nghiệm, nhưng rất có thể chúng sẽ trở nên tồi tệ hơn trong các trường hợp khác.

Thông thường, sendfilehàm có thể trả về trước khi ghi đã được cam kết, do đó tạo ấn tượng là nhanh hơn phần còn lại. Tôi chưa đọc mã, nhưng chắc chắn là vì nó phân bổ bộ đệm chuyên dụng của riêng nó, bộ nhớ giao dịch theo thời gian. Và lý do tại sao nó không hoạt động đối với các tệp lớn hơn 2Gb.

Miễn là bạn đang xử lý một số lượng nhỏ tệp, mọi thứ xảy ra bên trong các bộ đệm khác nhau (trước tiên là thời gian chạy của C ++ nếu bạn sử dụng iostream, các tệp bên trong của hệ điều hành, rõ ràng là một bộ đệm bổ sung có kích thước tệp trong trường hợp sendfile). Phương tiện lưu trữ thực tế chỉ được truy cập khi đủ dữ liệu đã được di chuyển xung quanh để xứng đáng với sự cố quay đĩa cứng.

Tôi cho rằng bạn có thể cải thiện một chút hiệu suất trong các trường hợp cụ thể. Off đỉnh đầu của tôi:

  • Nếu bạn đang sao chép một tệp lớn trên cùng một đĩa, sử dụng bộ đệm lớn hơn HĐH có thể cải thiện mọi thứ một chút (nhưng có lẽ chúng ta đang nói về gigabyte ở đây).
  • Nếu bạn muốn sao chép cùng một tệp trên hai đích vật lý khác nhau, có thể bạn sẽ nhanh chóng mở ba tệp cùng một lúc hơn là gọi hai tệp copy_file tuần tự (mặc dù bạn sẽ khó nhận thấy sự khác biệt miễn là tệp phù hợp với bộ đệm của hệ điều hành)
  • Nếu bạn đang xử lý nhiều tệp nhỏ trên ổ cứng, bạn có thể muốn đọc chúng theo đợt để giảm thiểu thời gian tìm kiếm (mặc dù HĐH đã lưu trữ các mục trong thư mục để tránh tìm kiếm như các tệp điên và nhỏ có thể sẽ làm giảm đáng kể băng thông đĩa).

Nhưng tất cả những gì nằm ngoài phạm vi của chức năng sao chép tệp mục đích chung.

Vì vậy, theo ý kiến ​​của lập trình viên dày dạn kinh nghiệm của tôi, một bản sao tệp C ++ chỉ nên sử dụng file_copychức năng chuyên dụng C ++ 17 , trừ khi biết nhiều hơn về bối cảnh xảy ra sao chép tệp và một số chiến lược thông minh có thể được đưa ra để vượt qua HĐH.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.