Bir dosyayı (ikili veya metin) kopyalamanın iyi bir yolunu arıyorum. Birkaç örnek yazdım, herkes çalışıyor. Ama tecrübeli programcıların görüşlerini duymak istiyorum.
İyi örnekler eksik ve C ++ ile çalışan bir şekilde arama.
ANSI-C YOLLU
#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 bunu "C programlama dili" de kullanır, daha düşük düzey)
#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 YOLLU
#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;
}
KOPYA-ALGORİTMASI-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İ-TAMPONU-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;
}
LINUX-WAY // çekirdek 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
- GNU / LINUX (Archlinux)
- Çekirdek 3.3
- GLIBC-2.15, LIBSTDC ++ 4.7 (GCC-LIBS), GCC 4.7, Coreutils 8.16
- RUNLEVEL 3'ü kullanma (Çok kullanıcılı, Ağ, Terminal, GUI yok)
- INTEL SSD-Postville 80 GB,% 50'ye kadar dolu
- 270 MB OGG-VİDEO DOSYASI 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 TIME kullanıldı)
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 aynı sonuçları yazdırın.
Video dosyası hala oynatılabilir.
Sorular
- Hangi yöntemi tercih edersiniz?
- Daha iyi çözümler biliyor musunuz?
- Kodumda herhangi bir hata görüyor musunuz?
Çözümden kaçınmak için bir neden biliyor musunuz?
FSTREAM (KISS, Streambuffer)
Bunu gerçekten seviyorum, çünkü gerçekten kısa ve basit. Bildiğim kadarıyla operatör << rdbuf () için aşırı yüklenmiş ve hiçbir şey dönüştürmez biliyorum. Doğru?
Teşekkürler
Güncelleme 1
Dosya tanımlayıcılarının açılıp kapanması, clock () ölçümüne dahil edilecek şekilde tüm örneklerde kaynağı değiştirdim . Bunlar kaynak kodunda başka önemli bir değişiklik değildir. Sonuçlar değişmedi! Sonuçlarımı tekrar kontrol etmek için de zaman kullandım .
Güncelleme 2
ANSI C örneği değişti: while- loop'un durumu artık feof () öğesini çağırmıyor, bunun yerine fread () öğesini koşula taşıdım . Görünüşe göre, kod şimdi 10.000 saat daha hızlı çalışıyor.
Ölçüm değişti: Önceki sonuçlar her zaman arabelleğe alındı, çünkü eski komut satırını rm to.ogv && sync && time ./program 'ı her program için birkaç kez tekrarladım. Şimdi her program için sistemi yeniden başlatıyorum. Tamponsuz sonuçlar yenidir ve sürpriz değildir. Tamponsuz sonuçlar gerçekten değişmedi.
Eski kopyayı silmezsem, programlar farklı tepki verir. Bir varolan dosyanın üzerine tamponlu hızlı POSIX ve SendFile ile, tüm diğer programlar yavaştır. Belki de kısaltılmış veya oluşturulmuş seçenekler bu davranış üzerinde bir etkiye sahiptir. Ancak aynı kopya ile mevcut dosyaların üzerine yazmak gerçek bir kullanım örneği değildir.
Kopyanın cp ile gerçekleştirilmesi, 0.44 saniye arabelleksiz ve 0.30 saniye ara belleğe alınır. Yani cp POSIX örneğinden biraz daha yavaştır. Benim için iyi görünüyor.
Belki de mmap () ve copy_file()
boost :: dosya sisteminden örnekler ve sonuçlar ekliyorum .
Güncelleme 3
Bunu bir blog sayfasına da koydum ve biraz genişlettim. Linux çekirdeğinden düşük seviyeli bir işlev olan splice () dahil . Belki Java ile daha fazla örnek gelecektir.
http://www.ttyhoney.com/blog/?page_id=69
#include <copyfile.h> copyfile(const char *from, const char *to, copyfile_state_t state, copyfile_flags_t flags);
fstream
kesinlikle dosya işlemleri için iyi bir seçenektir.