Ini adalah tindak lanjut dari Konversi metode string.endswith ke C, di mana saya (mencoba) mengonversi program python menjadi C.

Bagian selanjutnya adalah membaca data dengan benar dari file ke dalam buffer dan memeriksa berbagai tempat yang mungkin error. Inilah yang saya miliki sejauh ini:

#define BUFFER_SIZE 1024*10
char buffer[BUFFER_SIZE];

void exit_with_error(const char* msg)
{
    fprintf(stderr, "%s", msg);
    exit(EXIT_FAILURE);
}

int main(int argc, char* argv[])
{
     // with open(argv[-1) as f:
    //    contents = f.read()

    // 1. Open file
    FILE *fp = fopen(argv[argc-1], "r");
    if (fp == NULL) exit_with_error("Error reading file");

    // 2. Read and confirm BUFFER is OK
    fseek(fp, 0L, SEEK_END);
    long fsize = ftell(fp);
    if (fsize > BUFFER_SIZE) exit_with_error("File is larger than buffer.");

    // 3. Write to buffer and close.
    rewind(fp);
    size_t read_size = fread(buffer, 1, fsize, fp);
    if (read_size != fsize) exit_with_error("There was an error reading the file.");
    fclose(fp);

}

Saya punya beberapa pertanyaan di atas:

  • Untuk membaca file ke dalam buffer, apakah lebih umum untuk memiliki ukuran buffer standar dan menulisnya ke dalam buffer, atau untuk mengambil ukuran dan kemudian melakukan malloc. Apakah ada keuntungan dari satu cara di atas yang lain?
  • Apakah perlu melakukan semua pemeriksaan kesalahan ini dalam metode main, atau dapatkah saya berasumsi bahwa pengguna menyediakan file yang benar (dan dapat dibaca, dll.)?
  • Terakhir, mengapa beberapa metode file mengembalikan size_t dan lainnya mengembalikan long (seperti melakukan ftell?) Apakah aman menggunakan size_t untuk semuanya atau apakah ada alasan mengapa beberapa bukan tipe itu?
c
1
David542 9 April 2021, 00:23

1 menjawab

Jawaban Terbaik

Untuk membaca file ke dalam buffer, apakah lebih umum untuk memiliki ukuran buffer standar dan menulisnya ke dalam buffer, atau untuk mengambil ukuran dan kemudian melakukan malloc. Apakah ada keuntungan dari satu cara di atas yang lain?

"ambil ukuran" itu rumit. long fsize = ftell(fp); berfungsi sering, tetapi tidak ditentukan untuk mencapai tujuan panjang. Kode yang sangat portabel tidak menggunakan ftell().

Untuk membaca seluruh file, beberapa panggilan ke fread() adalah caranya.

Apakah perlu melakukan semua pemeriksaan kesalahan ini dalam metode utama, atau dapatkah saya berasumsi bahwa pengguna menyediakan file yang benar (dan dapat dibaca, dll.)?

Kode yang kuat menghindari membuat asumsi. Lebih baik menganggap masukan pengguna jahat (tonton video Kalium ) dan melakukan banyak pemeriksaan kesalahan.

Terakhir, mengapa beberapa metode file mengembalikan size_t dan lainnya mengembalikan long (seperti melakukan ftell?) Apakah aman menggunakan size_t untuk semuanya atau apakah ada alasan mengapa beberapa bukan tipe itu?

Rentang size_t biasanya didorong oleh ukuran memori dan arsitekturnya. Kisaran ukuran file adalah batasan sistem file. Tidak jarang ukuran file berpotensi melebihi ukuran memori. Ketika C pertama kali keluar long adalah jenis bertanda terbesar dan cukup untuk semua kasus hingga, katakanlah, sekitar tahun 1995. Sekarang file dapat melebihi 2G, (nilai maksimum minimum untuk long). Bahkan dengan long 32-bit, offset file yang besar dapat dilacak melalui fgetpos(). Banyak sistem yang lebih baru menggunakan long 64-bit, memungkinkan jangkauan yang lebih jauh melalui ftell().


Jika kode mencoba menemukan ukuran file dengan ftell() ....

Periksa ftell() dan hasil fungsi I/O lainnya.

if (fseek(fp, 0, SEEK_END);) {
  exit_with_error("fseek failure.");
}
long fsize = ftell(fp);
if (fsize == -1) {
  exit_with_error("ftell failure.");
}

// In many cases, files exceeding `SIZE_MAX` are also problematic.
// Yet rarely is LONG_MAX > SIZE_MAX
if (fsize > SIZE_MAX) {
  exit_with_error("fsize very large.");
}

Seringkali lebih diinginkan untuk membuka file dalam mode biner.


Terakhir, IMO, untuk menangani file, hindari kebutuhan untuk membaca semuanya ke dalam memori dan mengatasi data dalam potongan.

3
chux - Reinstate Monica 9 April 2021, 01:45