2009-02-13 38 views
5

Tôi đang thực hiện một dự án nhỏ trong C sau một thời gian khá xa nó. Những điều này xảy ra để bao gồm một số xử lý tệp. Tôi nhận thấy trong tài liệu khác nhau rằng có các chức năng mà trở về xử lý FILE * và những người khác quay trở lại (số nguyên nhỏ) mô tả. Cả hai bộ chức năng đều cung cấp các dịch vụ cơ bản giống nhau mà tôi cần vì vậy nó thực sự không quan trọng tôi sử dụng.Có bất kỳ lý do thông thường nào để sử dụng open() thay vì fopen() không?

Nhưng tôi tò mò về trí tuệ thu thập: có tốt hơn không khi sử dụng fopen() và bạn bè, hoặc open() và bạn bè?

Chỉnh sửa Vì ai đó đã đề cập đến các thiết bị đệm và không truy cập được, tôi nên thêm một phần của dự án nhỏ này sẽ viết trình điều khiển hệ thống tệp người dùng trong FUSE. Do đó, quyền truy cập cấp tệp có thể dễ dàng trên thiết bị (ví dụ: CDROM hoặc ổ đĩa SCSI) như trên "tệp" (tức là hình ảnh).

Trả lời

5

Phản đối "fopen" là di động và "mở" không phải là không có thật.

fopen là một phần của libc, mở là cuộc gọi hệ thống POSIX.

Mỗi thiết bị đều có thể di động như địa điểm của chúng.

i/o để fopen'ed tập tin là (bạn phải giả định nó có thể được, và cho mục đích thực tế, nó được) đệm bởi libc, tập tin mô tả mở() 'ed không được đệm bởi libc (họ cũng có thể được , và thường được đệm trong hệ thống tập tin - nhưng không phải mọi thứ bạn mở() là một tệp trên hệ thống tệp.

Điểm fopen'ing, ví dụ, nút thiết bị như/dev/sg0, hoặc/dev/tty0 ... Bạn sẽ làm gì? Bạn sẽ làm một ioctl trên một TẬP_TIN * Chúc bạn may mắn với điều đó

Có thể bạn muốn mở với một số cờ như O_DIRECT - làm cho không có ý nghĩa với fopen().

2

thường, bạn nên ưu tiên sử dụng thư viện chuẩn (fopen). Tuy nhiên, có những trường hợp bạn sẽ cần phải sử dụng mở trực tiếp.

Một ví dụ mà bạn cần lưu ý là làm việc xung quanh một lỗi trong phiên bản cũ hơn của solaris khiến fopen thất bại sau khi 256 tệp được mở. Điều này là do họ erroniously sử dụng một unsigned char cho lĩnh vực fd trong cấu trúc của họ FILE thực hiện thay vì một int. Nhưng đây là một trường hợp rất cụ thể.

+0

'Phiên bản cũ hơn của Solaris' bao gồm Solaris 10 (hiện tại) - ít nhất là đối với mã 32 bit. –

3

Có. Khi bạn cần một tay cầm cấp thấp.

Trên hệ điều hành UNIX, bạn thường có thể trao đổi các tay cầm và ổ cắm tệp.

Ngoài ra, các tay cầm cấp thấp giúp khả năng tương thích ABI tốt hơn so với con trỏ FILE.

+0

int fd = fileno (tệp);/* được một tay cầm cấp thấp từ một FILE * */ –

+0

LƯU Ý: fileno là posix và không c89/c99 mặc dù. –

+0

@Joshua: bạn có đề cập đến khả năng chuyển các bộ mô tả tệp giữa các quá trình (bí truyền, nhưng tôi biết phần mềm được thực hiện) hay thay đổi giữa các con trỏ tệp và bộ mô tả tệp hay cái gì khác? Hãy nhớ rằng, fdopen() có thể chuyển đổi một bộ mô tả tập tin thành một con trỏ tập tin. –

14

Nó là tốt hơn để sử dụng open() nếu bạn đang gắn bó với hệ thống unix-like và bạn có thể muốn:

  • Có kiểm soát nhiều hạt mịn trên bit quyền unix trên tạo tập tin.
  • Sử dụng các chức năng cấp thấp hơn như đọc/ghi/mmap như trái ngược với các chức năng I/O của luồng đệm.
  • Sử dụng lập trình mô tả tập tin (fd) dựa trên IO (thăm dò ý kiến, chọn, v.v.) Bạn có thể lấy một fd từ một FILE * sử dụng fileno(), nhưng không được trộn lẫn với hàm FILE * fd dựa trên chức năng.
  • mở bất kỳ thiết bị đặc biệt (không phải là một tập tin bình thường)

Nó là tốt hơn để sử dụng fopen/fread/fwrite cho tính di động tối đa, vì đây là những chức năng C tiêu chuẩn, chức năng tôi đã đề cập ở trên không .

+0

Tôi rất vui vì chúng tôi có ai đó đánh vần lợi ích của việc sử dụng mở() mỗi lần trong một thời gian. –

4

fopen công trình ở một mức độ cao hơn so với mở .... fopen trả về cho bạn một con trỏ đến FILE suối đó cũng tương tự như các dòng trừu tượng mà bạn đọc trong C++

mở trả về cho bạn một mô tả cho file mở ... Nó không cung cấp cho bạn một trừu tượng dòng và bạn có trách nhiệm xử lý các bit và byte chính mình ... Đây là ở một mức độ thấp hơn so với fopen

Luồng Stdio được đệm, trong khi mở() tập tin mô tả thì không. Phụ thuộc vào những gì bạn cần.Bạn cũng có thể tạo một cái khác:

int fileno (FILE * stream) trả về bộ mô tả tệp cho FILE *, FILE * fdopen (int fildes, const char * mode) tạo FILE * từ bộ mô tả tệp.

Hãy cẩn thận khi trộn lẫn bộ đệm đệm và không đệm, vì bạn sẽ mất những gì trong bộ đệm khi bạn không xóa nó bằng fflush().

0

fopen và người anh em họ của nó được đệm. mở, đọc và viết không được đệm. Ứng dụng của bạn có thể hoặc có thể không quan tâm.

fprintf và scanf có API phong phú hơn cho phép bạn đọc và ghi tệp văn bản được định dạng. đọc và ghi sử dụng các mảng cơ bản của các byte. Chuyển đổi và định dạng phải được tạo thủ công.

Sự khác biệt giữa các bộ mô tả tệp và (FILE *) thực sự không quan trọng.

Randy

+0

cho đến khi nó không phải là. –

2

read() & write() sử dụng bộ đệm I/O. (fd: mô tả tập tin số nguyên)

fread() & fwrite() sử dụng đệm I/O. (FILE con trỏ * cấu trúc)

Dữ liệu nhị phân bằng văn bản cho một đường ống với write()có thể không có thể đọc dữ liệu nhị phân với fread(), vì sự sắp xếp, byte, các kích thước khác nhau, v.v.

Hầu hết mã trình điều khiển thiết bị cấp thấp sử dụng các cuộc gọi I/O không được lọc.

Hầu hết I/O cấp ứng dụng đều sử dụng bộ đệm.

Sử dụng FILE * và chức năng liên quan của nó là OK trên cơ sở máy-by-máy: nhưng tính di động bị mất trên kiến ​​trúc khác trong đọc và viết dữ liệu nhị phân. fwrite() là bộ đệm I/O và có thể dẫn đến kết quả không đáng tin cậy nếu được viết cho kiến ​​trúc 64 bit và chạy trên 32 bit; hoặc (Windows/Linux). Hầu hết các hệ điều hành đều có macro tương thích trong mã riêng của chúng để ngăn chặn điều này.

Đối với cấp thấp nhị phân I/O di read()write() đảm bảo nhị phân cùng đọc và viết khi biên soạn trên kiến ​​trúc khác nhau. Điều cơ bản là chọn cách này hay cách khác và nhất quán về nó, trong suốt bộ nhị phân.

<stdio.h> // mostly FILE* some fd input/output parameters for compatibility 
      // gives you a lot of helper functions --> 
List of Functions 
     Function  Description 
     ─────────────────────────────────────────────────────────────────── 
     clearerr  check and reset stream status 
     fclose  close a stream 
     fdopen  stream open functions //(fd argument, returns FILE*)      feof   check and reset stream status 
     ferror  check and reset stream status 
     fflush  flush a stream 
     fgetc   get next character or word from input stream 
     fgetpos  reposition a stream 
     fgets   get a line from a stream 
     fileno  get file descriptor // (FILE* argument, returns fd) 
     fopen   stream open functions 
     fprintf  formatted output conversion 
     fpurge  flush a stream 
     fputc   output a character or word to a stream 
     fputs   output a line to a stream 
     fread   binary stream input/output 
     freopen  stream open functions 
     fscanf  input format conversion 
     fseek   reposition a stream 
     fsetpos  reposition a stream 
     ftell   reposition a stream 
     fwrite  binary stream input/output 
     getc   get next character or word from input stream 
     getchar  get next character or word from input stream 
     gets   get a line from a stream 
     getw   get next character or word from input stream 
     mktemp  make temporary filename (unique) 
     perror  system error messages 
     printf  formatted output conversion 
     putc   output a character or word to a stream 
     putchar  output a character or word to a stream 
     puts   output a line to a stream 
     putw   output a character or word to a stream 
     remove  remove directory entry 
     rewind  reposition a stream 
     scanf   input format conversion 
     setbuf  stream buffering operations 
     setbuffer  stream buffering operations 
     setlinebuf stream buffering operations 
     setvbuf  stream buffering operations 
     sprintf  formatted output conversion 
     sscanf  input format conversion 
     strerror  system error messages 
     sys_errlist system error messages 
     sys_nerr  system error messages 
     tempnam  temporary file routines 
     tmpfile  temporary file routines 
     tmpnam  temporary file routines 
     ungetc  un-get character from input stream 
     vfprintf  formatted output conversion 
     vfscanf  input format conversion 
     vprintf  formatted output conversion 
     vscanf  input format conversion 
     vsprintf  formatted output conversion 
     vsscanf  input format conversion 

Vì vậy, để sử dụng cơ bản, cá nhân tôi sẽ sử dụng ở trên mà không trộn thành ngữ quá nhiều.

Ngược lại,

<unistd.h> write() 
      lseek() 
      close() 
      pipe() 
<sys/types.h> 
<sys/stat.h> 
<fcntl.h> open() 
      creat() 
      fcntl() 
all use file descriptors. 

Những cung cấp kiểm soát hạt mịn hơn đọc và viết byte (khuyến khích cho các thiết bị đặc biệt và FIFOs (ống)).

Vì vậy, một lần nữa, sử dụng những gì bạn cần, nhưng hãy nhất quán trong các thành ngữ và giao diện của bạn. Nếu hầu hết cơ sở mã của bạn sử dụng một chế độ, hãy sử dụng chế độ đó, trừ khi có lý do thực sự không. Cả hai bộ chức năng thư viện I/O đều cực kỳ đáng tin cậy và được sử dụng hàng triệu lần mỗi ngày.

note-- Nếu bạn đang interfacing CI/O với một ngôn ngữ khác, (perl, python, java, C#, lua ...) séc ra những gì các nhà phát triển trong những ngôn ngữ khuyên trước khi bạn viết mã C của bạn và tiết kiệm cho mình một số rắc rối.

+0

"nhưng tính di động bị mất trên các kiến ​​trúc khác trong việc đọc và ghi dữ liệu nhị phân. Fwrite() được đệm I/O và có thể dẫn đến kết quả không đáng tin cậy nếu được viết cho kiến ​​trúc 64 bit và chạy trên 32 bit hoặc (Windows/Linux). " - điều này hoàn toàn không đúng sự thật. tất cả những gì bạn cần làm là đảm bảo mở tệp ở chế độ BINARY – minexew

Các vấn đề liên quan