C fopen vs mở


219

Có bất kỳ lý do (ngoài những cú pháp) mà bạn muốn sử dụng

FILE *fdopen(int fd, const char *mode);

hoặc là

FILE *fopen(const char *path, const char *mode);

thay vì

int open(const char *pathname, int flags, mode_t mode);

Khi sử dụng C trong môi trường Linux?


Ý của bạn là fdopenopenhay fopenopen?
dùng7116

Ý bạn là fopen, không phải fdopen?
Omnifarious

9
fopenlà một phần của thư viện C tiêu chuẩn, openthì không. Sử dụng fopenkhi viết mã di động.
Aziz

Vâng, tôi có nghĩa là fopen. Tôi chỉ cập nhật nó, nhưng tôi nghĩ nguyên tắc tương tự được áp dụng.
LJM

6
@Aziz, openlà một chức năng POSIX.
dreamlax

Câu trả lời:


242

Đầu tiên, không có lý do đặc biệt tốt để sử dụng fdopennếu fopenlà một tùy chọn và openlà lựa chọn khả thi khác. Bạn không nên sử dụng openđể mở tệp ở vị trí đầu tiên nếu bạn muốn a FILE *. Vì vậy, bao gồm fdopentrong danh sách đó là không chính xác và khó hiểu bởi vì nó không giống như những người khác. Bây giờ tôi sẽ tiến hành bỏ qua nó vì sự khác biệt quan trọng ở đây là giữa một tiêu chuẩn C FILE *và một mô tả tệp dành riêng cho hệ điều hành.

Có bốn lý do chính để sử dụng fopenthay vì open.

  1. fopencung cấp cho bạn bộ đệm IO có thể nhanh hơn rất nhiều so với những gì bạn đang làm open.
  2. fopen thực hiện dịch kết thúc dòng nếu tệp không được mở ở chế độ nhị phân, điều này có thể rất hữu ích nếu chương trình của bạn được chuyển sang môi trường không phải là Unix (mặc dù thế giới dường như chỉ hội tụ trên mạng thôi (trừ mạng dựa trên văn bản IETF các giao thức như SMTP và HTTP và như vậy)).
  3. A FILE *cung cấp cho bạn khả năng sử dụng fscanfvà các chức năng stdio khác.
  4. Mã của bạn một ngày nào đó có thể cần phải được chuyển sang một số nền tảng khác chỉ hỗ trợ ANSI C và không hỗ trợ openchức năng.

Theo ý kiến ​​của tôi, bản dịch kết thúc dòng thường cản trở bạn hơn là giúp bạn và việc phân tích cú pháp fscanfyếu đến mức bạn chắc chắn sẽ ném nó ra để ủng hộ thứ gì đó hữu ích hơn.

Và hầu hết các nền tảng hỗ trợ C đều có openchức năng.

Điều đó để lại câu hỏi đệm. Ở những nơi bạn chủ yếu đọc hoặc viết một tệp tuần tự, hỗ trợ bộ đệm thực sự hữu ích và cải thiện tốc độ lớn. Nhưng nó có thể dẫn đến một số vấn đề thú vị trong đó dữ liệu không kết thúc trong tệp khi bạn mong đợi nó ở đó. Bạn phải nhớ fclosehoặc fflushvào những thời điểm thích hợp.

Nếu bạn đang làm tìm kiếm (aka fsetposhoặc fseekthứ hai trong số đó là một chút phức tạp hơn để sử dụng một cách phù hợp tiêu chuẩn), tính hữu ích của đệm nhanh chóng đi xuống.

Tất nhiên, sự thiên vị của tôi là tôi có xu hướng làm việc với các socket rất nhiều, và có một thực tế là bạn thực sự muốn thực hiện IO không chặn (điều này FILE *hoàn toàn không hỗ trợ theo bất kỳ cách hợp lý nào) mà không có bộ đệm nào cả và thường xuyên có yêu cầu phân tích phức tạp thực sự tô màu nhận thức của tôi.


4
Tôi sẽ không đặt câu hỏi về trải nghiệm của bạn, nhưng tôi rất muốn nghe bạn giải thích một chút về điều này. Đối với loại ứng dụng nào bạn cảm thấy rằng bộ đệm tích hợp có thể cản trở? Chính xác thì vấn đề là gì?
Emil H

1
Không thấy đoạn cuối. Điểm hợp lệ, IMHO. Theo như tôi có thể nói câu hỏi là về tập tin IO.
Emil H

7
Để làm rõ khi đệm được cản trở. Đó là khi bạn sử dụng tìm kiếm. Sau khi đọc với bất cứ lệnh ( fgets, fgetc, fscanf, fread), sẽ luôn luôn đọc toàn bộ kích thước của bộ đệm (4K, 8K hoặc bất cứ điều gì bạn thiết lập). Bằng cách sử dụng I / O trực tiếp, bạn có thể tránh điều đó. Trong trường hợp đó, tốt hơn là sử dụng preadthay vì cặp tìm kiếm / đọc (1 tòa nhà thay vì 2).
Patrick Schlüter

2
Xử lý các cuộc gọi bị gián đoạn read()write()là một lý do thứ năm thuận tiện để sử dụng họ hàm libc.
nccc

3
@ m-ric: Vâng, đó là một câu hỏi không liên quan, nhưng có. Tất cả các nền tảng hỗ trợ ioctlcũng hỗ trợ filenocuộc gọi nhận FILE *và trả về một số có thể được sử dụng trong ioctlcuộc gọi. Hãy cẩn thận. FILE *các cuộc gọi liên quan có thể tương tác đáng ngạc nhiên với việc sử dụng ioctlđể thay đổi điều gì đó về bộ mô tả tệp cơ bản.
có nhiều thứ

53

open()là một cuộc gọi os cấp thấp. fdopen()chuyển đổi một bộ mô tả tệp cấp độ os thành bản tóm tắt FILE cấp cao hơn của ngôn ngữ C. fopen()gọi open()trong nền và cung cấp cho bạn một con trỏ TẬP_TIN trực tiếp.

Có một số lợi thế khi sử dụng các đối tượng FILE thay vì mô tả tệp thô, bao gồm dễ sử dụng hơn nhưng cũng có các lợi thế kỹ thuật khác như bộ đệm tích hợp. Đặc biệt là bộ đệm nói chung dẫn đến một lợi thế hiệu suất đáng kể.


3
Có bất kỳ nhược điểm nào khi sử dụng các phiên bản mở của bộ đệm 'f ...' không?
LJM

5
@L. Moser, vâng, khi bạn đã đệm dữ liệu, và do đó bộ đệm bổ sung thêm chi phí sao chép và bộ nhớ không cần thiết.
Michael Aaron Safyan

6
thực sự có những nhược điểm khác fopen()không cung cấp cùng mức kiểm soát khi mở tệp, ví dụ: tạo quyền, chế độ chia sẻ và hơn thế nữa. thông thường open()và các biến thể cung cấp nhiều quyền kiểm soát hơn, gần với những gì hệ điều hành thực sự cung cấp
Matt Joiner

2
Ngoài ra còn có các trường hợp cực đoan khi bạn mmaptập tin và thay đổi với I / O bình thường (thật không thể tin được là chúng tôi thực sự làm điều đó trong dự án của chúng tôi và vì lý do thực sự tốt), bộ đệm sẽ được thực hiện.
Patrick Schlüter

Bạn cũng có thể muốn sử dụng các chức năng hệ thống khác, như sử dụng open () để tải trước các tệp vào bộ đệm trang thông qua readahead (). Tôi đoán quy tắc của ngón tay cái là "sử dụng fopen trừ khi bạn thực sự cần open ()", open () thực sự cho phép bạn làm những thứ ưa thích (cài đặt / không đặt O_ATIME và tương tự).
Tomas Pruzina

34

fopen vs mở trong C

1) fopenlà một chức năng thư viện trong khi openlà một cuộc gọi hệ thống .

2) fopencung cấp đệm IO được nhanh hơn so sánh với openđó là phi Buffered .

3) fopendi động trong khi openkhông di động ( mở là môi trường cụ thể ).

4) fopentrả về một con trỏ tới cấu trúc FILE (FILE *) ; opentrả về một số nguyên xác định tệp.

5) A FILE *cung cấp cho bạn khả năng sử dụng fscanf và các chức năng stdio khác.


9
openlà một tiêu chuẩn POSIX, vì vậy nó khá di động
osvein

12

Trừ khi bạn là một phần của 0,1% ứng dụng mà việc sử dụng openlà lợi ích hiệu suất thực tế, thực sự không có lý do chính đáng nào để không sử dụng fopen. Theo như fdopencó liên quan, nếu bạn không chơi với các mô tả tập tin, bạn không cần cuộc gọi đó.

Stick với fopenvà gia đình của các phương pháp ( fwrite, fread, fprintf, et al) và bạn sẽ được rất hài lòng. Cũng quan trọng, các lập trình viên khác sẽ hài lòng với mã của bạn.


11

Nếu bạn có một FILE *, bạn có thể sử dụng các chức năng như fscanf, fprintffgetsvv Nếu bạn có chỉ là mô tả tập tin, bạn có giới hạn (nhưng có thể nhanh hơn) đầu vào và đầu ra thói quen read, writevv


7

Sử dụng mở, đọc, viết có nghĩa là bạn phải lo lắng về sự xen kẽ tín hiệu.

Nếu cuộc gọi bị gián đoạn bởi bộ xử lý tín hiệu, các chức năng sẽ trả về -1 và đặt errno thành EINTR.

Vì vậy, cách thích hợp để đóng một tập tin sẽ là

while (retval = close(fd), retval == -1 && ernno == EINTR) ;

4
Đối với close, điều này phụ thuộc vào hệ điều hành. Không đúng khi thực hiện vòng lặp trên Linux, AIX và một số hệ điều hành khác.
strcat

Ngoài ra, sử dụng đọc và ghi sẽ gặp vấn đề tương tự, nghĩa là chúng có thể bị gián đoạn bởi tín hiệu trước khi xử lý hoàn toàn đầu vào / đầu ra và lập trình viên phải xử lý các tình huống như vậy, trong khi xử lý tín hiệu bị gián đoạn và xử lý tín hiệu bị gián đoạn.
Marcelo

6

open()là một cuộc gọi hệ thống và dành riêng cho các hệ thống dựa trên Unix và nó trả về một bộ mô tả tệp. Bạn có thể viết thư cho một bộ mô tả tập tin bằng cách sử dụng write()một cuộc gọi hệ thống khác.
fopen()là một lệnh gọi hàm ANSI C trả về một con trỏ tệp và nó có thể được chuyển sang các hệ điều hành khác. Chúng ta có thể ghi vào một con trỏ tập tin bằng cách sử dụng fprintf.

Trong Unix:
Bạn có thể lấy một con trỏ tệp từ bộ mô tả tệp bằng cách sử dụng:

fP = fdopen(fD, "a");

Bạn có thể lấy một bộ mô tả tệp từ con trỏ tệp bằng cách sử dụng:

fD = fileno (fP);

4

open () sẽ được gọi ở cuối mỗi hàm fopen () . open () là một cuộc gọi hệ thống và fopen () được các thư viện cung cấp dưới dạng hàm bao bọc để người dùng dễ sử dụng


2

Tôi đã thay đổi thành open () từ fopen () cho ứng dụng của mình, bởi vì fopen đã gây ra số lần đọc hai lần mỗi khi tôi chạy fopen fgetc. Đọc đôi đã làm gián đoạn những gì tôi đang cố gắng thực hiện. open () dường như làm những gì bạn yêu cầu.


2

Cũng phụ thuộc vào những gì cờ được yêu cầu để mở. Đối với việc sử dụng để viết và đọc (và tính di động) f * nên được sử dụng, như đã lập luận ở trên.

Nhưng nếu về cơ bản muốn chỉ định nhiều hơn các cờ tiêu chuẩn (như cờ rw và chắp thêm), bạn sẽ phải sử dụng API cụ thể của nền tảng (như POSIX mở) hoặc thư viện tóm tắt các chi tiết này. Tiêu chuẩn C không có bất kỳ cờ nào như vậy.

Ví dụ, bạn có thể muốn mở một tệp, chỉ khi nó thoát. Nếu bạn không chỉ định cờ tạo, tệp phải tồn tại. Nếu bạn thêm độc quyền để tạo, nó sẽ chỉ tạo tệp nếu nó không tồn tại. Chúng còn nhiều nữa.

Ví dụ, trên các hệ thống Linux, có một giao diện LED được hiển thị thông qua các sysfs. Nó cho thấy độ sáng của đèn led thông qua một tập tin. Viết hoặc đọc một số dưới dạng một chuỗi từ 0-255. Tất nhiên bạn không muốn tạo tập tin đó và chỉ ghi vào nó nếu nó tồn tại. Điều thú vị bây giờ: Sử dụng fdopen để đọc / ghi tệp này bằng các cuộc gọi tiêu chuẩn.


0

mở tệp bằng fopen
trước khi chúng ta có thể đọc (hoặc ghi) thông tin từ (đến) tệp trên đĩa, chúng ta phải mở tệp. để mở tập tin chúng ta đã gọi hàm fopen.

1.firstly it searches on the disk the file to be opened.
2.then it loads the file from the disk into a place in memory called buffer.
3.it sets up a character pointer that points to the first character of the buffer.

Đây là cách hành xử của chức năng fopen
có một số nguyên nhân trong khi quá trình đệm, nó có thể hết thời gian. Vì vậy, trong khi so sánh fopen (i / o cấp cao) với cuộc gọi hệ thống mở (i / o cấp thấp), và nó nhanh hơn thích hợp hơn fopen .


mở nhanh hơn fopen?
obayhan 7/12/2016

vâng, mở là cuộc gọi hệ thống, nhanh hơn fopen - so sánh @obayhan
prashad
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.