Utilitas untuk menukar dua file
Meskipun saya tidak pernah harus menukar dua file, saya selalu bertanya-tanya apakah ada perintah untuk menukar dua file dan baru-baru ini saya memutuskan untuk melihat apakah ada satu file. Akhirnya saya menemukan bahwa tidak ada satu pun dan sebagai hasilnya saya memutuskan untuk membuatnya.
Ini kodenya: main.cc
#include <iostream>
#include <filesystem>
#include <cstring>
#include <cassert>
static auto print_help() -> void {
std::cout << "Usage: swap [file1] [file2]\n";
std::cout << "swaps the contents of file1 and file2\n";
std::cout << "use swap --help to print this message\n";
}
static auto validate_files(const std::filesystem::path& file1_path, const std::filesystem::path& file2_path) -> void {
{
/* check if file exists */
const auto file1_exists = std::filesystem::exists(file1_path);
const auto file2_exists = std::filesystem::exists(file2_path);
const auto exists = file1_exists && file2_exists;
if (!exists) {
if (!file1_exists) std::cerr << "cannot find file " << file1_path << '\n';
if (!file2_exists) std::cerr << "cannot find file " << file2_path << '\n';
exit(EXIT_FAILURE);
}
}
{
if (file1_path == file2_path) {
std::cerr << "swaping the same two files does nothing\n";
exit(EXIT_SUCCESS);
}
}
}
static auto get_temp_filename(char* template_name) -> void {
/* tmpnam_s does not work on linux */
#if defined(WIN32) || defined(_WIN32)
errno_t err = tmpnam_s(template_name, L_tmpnam);
assert(!err);
#else
int err = mkstemp(template_name);
assert(err != -1);
#endif
}
int main(int argc, char** argv) {
std::ios::sync_with_stdio(false);
switch (argc) {
case 2: {
/* convert the second arg to upper case */
std::transform(argv[1],
argv[1] + strlen(argv[1]),
argv[1],
::toupper);
if (!strcmp(argv[1], "--HELP")) {
print_help();
return EXIT_SUCCESS;
}
else {
std::cerr << "Invalid args see --help for usage\n";
return EXIT_FAILURE;
}
}
case 3:
break;
default: {
std::cerr << "Invalid args see --help for usage\n";
return EXIT_FAILURE;
}
}
const auto file1_path = std::filesystem::path{ argv[1] };
const auto file2_path = std::filesystem::path{ argv[2] };
validate_files(file1_path, file2_path);
char temp_filename[L_tmpnam] = "XXXXXX";
get_temp_filename(temp_filename);
const auto temp_filepath = std::filesystem::path{ temp_filename };
/* move-swap the files instead of copy-swaping */
/* renaming a file is the same as moving it */
std::filesystem::rename(file1_path, temp_filepath);
std::filesystem::rename(file2_path, file1_path);
std::filesystem::rename(temp_filepath, file2_path);
}
Berikut ini contoh penggunaan:
swap doc1.txt doc2.txt
Jawaban
file1_path == file2_path
pasti memberi tahu bahwa jalur merujuk ke file yang sama. Namun, meskipunfile1_path != file2_path
mereka masih merujuk ke file yang sama.file1_exists = std::filesystem::exists(file1_path);
memperkenalkan kondisi balapan TOC-TOU. File mungkin ada pada saat pengujian, namun menghilang saat digunakan. Lihat poin berikutnya.std::filesystem::rename
mungkin gagal. Anda menyebutnya waktu pohon. Jika panggilan kedua, atau ketiga gagal (dengan pengecualian!), Sistem file berakhir tidak persis seperti yang diharapkan. Gunakannoexcept
kelebihan beban, ujierror_code
setelah setiap panggilan, dan putar kembali semua tindakan sebelum kegagalan. Itu juga akan secara otomatis menangani jalur yang tidak ada.Jangan
assert
. Ini hanya bagus untuk menangkap bug, bukan masalah runtime. Dalam kode produksi (dikompilasi dengan-DNDEBUG
) itu tidak melakukan apa-apa, dan program Anda tidak akan mendeteksimkstemp
kegagalan.Program diam-diam tidak melakukan apa pun jika dipanggil dengan, katakanlah, 4 argumen. Ini juga membutuhkan banyak usaha jika dipanggil dengan 2 argumen. Menelepon
print_help()
kapan sajaargc != 3
jauh lebih mudah.
Saya menduga 'pertanyaan' itu meminta kritik kode. Jika saya salah tentang itu, mohon berhati-hati .. LOL
Kesan pertama saya adalah keterbacaan utama. Sakelar penguraian argumen besar menyembunyikan logika yang lebih penting ..
Mungkin membuatnya lebih mudah untuk dibaca (objek string dan perbandingan tidak peka huruf besar / kecil?) .. Bahkan lebih baik: masukkan ke metode pembantu rumah tangga.
(Juga: Kadang-kadang sederhana tidak apa-apa. Jika Anda tidak menerima dua argumen nama file, Anda dapat segera melontarkan bantuan, daripada memberi tahu pengguna untuk meminta bantuan secara eksplisit.)