SORU
17 NİSAN 2012, Salı


Kopyalama aklı başında, güvenli ve verimli bir şekilde dosya

Ben bir dosya kopyalamak için iyi bir yol (ikili veya metin) arayın. Birkaç örnek yazdım, herkes çalışıyor. Ama tecrübeli programcılar görüşünü duymak istiyorum.

İyi örnekler eksik ve C ile çalışan bir yol arama .

ANSI-C-YOL

#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 YÖNLÜ(K&R "C dili", daha düşük seviye) programlama . bu kullan

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

-C ÖPÜCÜK-Streambuffer YÖNLÜ

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

-ALGORİTMA-KOPYALA C -YOL

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

KENDİ-TAMPON-C -YOL

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

LİNUX-YOL// kernel ^ gerektirir . = 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;
}

Çevre

  • /LİNUX (Archlinux) GNU
  • Çekirdek 3.3
  • Abone olarak giriş-2.15, LİBSTDC 4.7 (GCC-LİBS), 4.7, 8.16 Coreutils GCC
  • Kullanarak çalışma SEVİYESİ 3 (çok Kullanıcılı, Ağ, Terminal, hiçbir GUI)
  • INTEL SSD-Postville 80 GB, 50'si kadar dolu
  • OGG-VİDEO-DOSYA 270 MB kopyalayın

Yeniden oluşturma adımları

 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

Sonuçlar (CPU ZAMAN kullanılır)

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  

Dosya boyutu değişmez.
sha256sum baskı aynı sonuçlar.
Video dosyası hala oynanabilir.

Soru

  • Hangi yöntemi tercih edersiniz?
  • Daha iyi çözümler biliyor musunuz?
  • Benim kodunda herhangi bir hata görüyor musunuz?
  • Bir çözüm önlemek için bir neden biliyor musunuz?

  • FSTREAM (ÖPÜCÜK, Streambuffer)
    Gerçekten çok kısa ve basit, çünkü bunun gibi. Kadarıyla biliyorum ben operatör << rdbuf için aşırı() ve bir şeye dönüştürmek değildir. Doğru mu?

Teşekkürler

Güncelleme 1
Dosya tanımlayıcıları açık ve yakın bir ölçü vardır bu şekilde tüm örneklerde kaynağını değiştirdim() saat. Kaynak kod içinde başka önemli değişiklikleri. Sonuçlar değişmiş değil! Ben de kullanılıyorzamançift kontrol sonuçlarım.

Güncelleme 2
ANSI C örnek değiştirdi: bu durumudöngüartık aramıyor() feofyerine taşındım() freadbir durum değildir. Görünüşe göre, kodu şimdi 10.000 saat daha hızlı çalışır.

Ölçü değişti: eski sonuçlar eski komut satırı tekrar ettim çünkü her zaman tamponlu idirm.ogv && senkron && zaman ./programher program bir kaç kez. Şimdi her program için sistemi yeniden başlatın. Adet sonuçlarını yeni ve sürpriz gösterin. Olmakta, sonuçlar gerçekten çok değişti olmadı.

Eğer eski bir kopyasını silmek istemiyorum eğer doğru değilse, program farklı tepki. Varolan bir dosyanın üzerinetamponluPOSIX ile daha hızlı ve SENDFİLE, tüm diğer programlar daha yavaş. Belki de seçeneklerikesecekyaoluşturunbu davranışı üzerinde bir etkisi vardır. Ama gerçek bir dünya değil aynı kopya ile üzerine dosya-case kullanın.

Kopya ile sahnecp0.44 saniyede bir adet alır ve 0.30 saniye tamponlu. Bu yüzdencpbiraz POSIX örnek daha yavaştır. Görünüyor benim için gayet iyi.

Belki de örnekleri ve sonuçları ekliyorum() yüksekvecopy_file()boost::dosya sistemi.

Güncelleme 3
Ayrıca bir blog sayfası bu koydum ve biraz genişletilmiş. Dahil() birleşmeLinux çekirdeği düşük seviyeli bir fonksiyonu olan., Belki Java ile daha çok örnek takip edecek. http://www.ttyhoney.com/blog/?page_id=69

CEVAP
17 NİSAN 2012, Salı


Aklı başında bir şekilde: bir dosya kopyalama

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

     dst << src.rdbuf();
 }

Bu çok basit ve sezgisel ekstra maliyet buna değer okunur. Eğer yapıyor olsaydık çok daha iyi bir dosya sistemi OS çağrıları geri düşmek. boost dosya sistemi kendi sınıfında dosya kopyalama yöntemi vardır eminim.

Dosya sistemi ile etkileşim için C bir yöntem var:

 #include <copyfile.h>

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

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Branboy3

    Branboy3

    12 AĞUSTOS 2012
  • FattySpins's channel

    FattySpins's

    17 Mayıs 2009
  • Michael Lummio

    Michael Lumm

    25 Mayıs 2007